Kotlin — настройка свойств расширения для изменяемого подкласса

#kotlin #properties #extension-methods

#kotlin #свойства #расширение-методы

Вопрос:

Предположим, что я хочу иметь свойство для List , а затем расширить это свойство с помощью средства установки для MutableList . Например, я хочу иметь средство получения для последнего элемента в списке, а также средство установки, если список является изменяемым. Итак, я хочу следующее:

 val <T> List<T>.myLast
    get() = this.last()

var <T> MutableList<T>.myLast: T
    set(value) {
        this[this.size - 1] = value
    }
  

Но это не компилируется. Можно ли этого достичь? Самые близкие вещи, которые я могу сделать:

  1. Объявите другое свойство:

     val <T> List<T>.myLast
        get() = this.last()
    
    var <T> MutableList<T>.myMutableLast: T
        get() = this.last()
        set(value) {
            this[this.size - 1] = value
        }
      

    Мне это не нравится, потому что я хочу иметь то же имя.

  2. Создайте средство получения и средство установки явно:

     fun<T> List<T>.getMyLast() = this.last()
    
    fun<T> MutableList<T>.setMyLast(value : T) {
        this[this.size - 1] = value
    }
      

    Мне это не нравится, потому что у него нет синтаксиса свойств.

Ответ №1:

Просто добавьте средство получения ко второму свойству, которое вызывает первое:

 val <T> List<T>.myLast
    get() = this.last()

var <T> MutableList<T>.myLast: T
    @JvmName("someName")
    get() = (this as List<T>).myLast
    set(value) {
        this[this.size - 1] = value
    }
  

В этом случае вы могли бы сделать то же самое get() = this.last() , но таким образом изменение первого определения автоматически влияет на второе.

Это будет разрешено так же, как и перегрузка метода, так что, например

 val x: List<String> = mutableListOf("")
val y: MutableList<String> = mutableListOf("")
x.myLast // calls List<T>.myLast.get()
y.myLast // calls MutableList<T>.myLast.get()
  

Комментарии:

1. Спасибо за ответ. Вы имеете в виду, что я сначала объявляю val <T> List<T>.myLast get() = this.last() , а затем то, что вы написали? Тогда я получаю "Platform declaration clash: The following declarations have the same JVM signature ...: fun List<T>.<get-myLast>(): ... fun MutableList<T>.<get-myLast>(): ..." .

2. Ах да, я упустил из виду, что это произойдет в данном конкретном случае, потому что List и MutableList сопоставлены с одним и тем же типом. Итак, вам нужна @JvmName аннотация к одному из средств получения.