Недавно я работал со списками в kotlin и получил следующий фрагмент:

a = listOf(1, 2, 3, 4)
println(a[-2])

Конечно, это вызывает IndexOutOfBoundsException, поэтому я подумал, что было бы неплохо расширить эту функциональность. Поэтому я подумал, что можно переопределить оператор get в классе List:

operator fun <T> List<T>.get(index: Int): T =
        // Here this should call the non-overridden version of
        // get. 
        get(index % size)

Я понимаю, что расширения - это просто статические методы, поэтому их нельзя переопределить, но есть ли способ добиться чего-то подобного?

Конечно, вы могли бы просто создать другую функцию

fun <T> List<T>.safeGet(index: Int): T = get(index % size)

Но хотелось бы знать, есть ли другие способы.

(Я понимаю, что index % size - очень наивный способ делать то, что я хочу, но это не является основной темой моего вопроса и делает код меньше.)

ИЗМЕНИТЬ

Когда я писал этот вопрос, я думал, что оператор % всегда будет возвращать положительные числа, когда правая часть положительна - как в python. Я сохраняю исходный вопрос здесь только для единообразия.

2
Fred 14 Мар 2018 в 12:01

2 ответа

Лучший ответ

Вы пытаетесь сделать что-то невозможное, потому что расширения всегда закрываются участниками, даже @JvmName не может вас спасти.

Обходной путь: используйте второе решение или добавьте параметр Unit, который некрасиво (выглядит как a[x, Unit]), но может существовать вместе с собственным методом get.

Другое решение: создайте собственную реализацию List (рекомендуется).

2
ice1000 14 Мар 2018 в 09:09

Поскольку оператор get уже определен в List, вы не можете переопределить get (с одним параметром Int). Однако вы можете переопределить оператор invoke, который не определен в List.

fun main(args: Array<String>) {
    val a = listOf(1, 2, 3, 4)
    println(a(-2))
}

// If `index` is negative, `index % size` will be non-positive by the definition of `rem` operator.
operator fun <T> List<T>.invoke(index: Int): T = if (index >= 0) get(index % size) else get((-index) % (-size))

Хотя я думаю, что создание нового метода расширения для List с соответствующим именем будет более предпочтительным вариантом.

Кстати, (positive value) % (negative value) неотрицательно, а (negative value) % (positive value) неотрицательно.
% в Kotlin соответствует rem в Haskell в следующем примере: https://stackoverflow.com/a / 28027235/869330

2
Naetmul 14 Мар 2018 в 09:34