Вызовы grid[1, 0] и 3 in grid не компилируются — найдите и исправьте ошибку
Grid приходит из библиотеки, которую вы не можете менять. Два расширения ниже должны обслуживать индексирование и проверку вхождения в main, но ни одно место вызова не компилируется.
Ограничения: не трогайте Grid, оставьте оба помощника расширениями и сохраните места вызова grid[1, 0] и 3 in grid ровно в том виде, как они написаны.
class Grid(val cells: List<Int>, val width: Int) // класс библиотеки — не редактировать
fun Grid.at(x: Int, y: Int): Int = cells[y * width + x]
fun Grid.has(value: Int): Boolean = cells.contains(value)
fun main() {
val grid = Grid(listOf(1, 2, 3, 4), 2)
println(grid[1, 0]) // не компилируется
println(3 in grid) // не компилируется
}
Найдите и исправьте ошибку.
Форма оператора разрешается только в функцию с условным именем, помеченную operator. Переименуйте at в get, а has в contains и пометьте обе operator: расширение может нести это слово, поэтому класс библиотеки править не нужно.
- ✗Считать, что оператор обязан быть членом класса и не может быть расширением
- ✗Оставлять произвольное имя вроде
atилиhasвместо условного - ✗Забывать, что для работы
inфункцияcontainsобязана возвращатьBoolean
- →Что сделает компилятор, если у класса уже есть член
getс такой же сигнатурой? - →Какое соглашение вы добавите, чтобы заработал и
for (cell in grid)?
Почему это не компилируется
Оператор в Kotlin — это не произвольная функция. grid[1, 0] компилятор разворачивает в grid.get(1, 0), а 3 in grid — в grid.contains(3). Имена at и has под соглашение не подходят, и даже с правильными именами вызов не соберётся без ключевого слова operator.
Исправление
class Grid(val cells: List<Int>, val width: Int) // класс библиотеки не тронут
operator fun Grid.get(x: Int, y: Int): Int = cells[y * width + x]
operator fun Grid.contains(value: Int): Boolean = cells.contains(value)
fun main() {
val grid = Grid(listOf(1, 2, 3, 4), 2)
println(grid[1, 0]) // 2
println(3 in grid) // true
}
Расширение имеет полное право нести operator, поэтому оператор добавляется к чужому классу без наследования и без правки библиотеки. Соглашение фиксирует и сигнатуру: contains обязана возвращать Boolean, иначе in не скомпилируется.
Если бы у Grid уже был член get с такой же сигнатурой, победил бы он: член всегда выигрывает у расширения.