Kotlin массив свойств с пользовательскими геттерами - PullRequest
0 голосов
/ 01 февраля 2019

Скажите, у меня есть это:

class NumWithSuccessor {
    var num = 1
    val successor
        get() = num + 1
}

Теперь, если я хочу вместо этого массив num s,

class NumsWithSuccessors {
    var nums = Array<Int>(3){ 1 }
    val successor
        get() = /* What? */
}

Мое первое предположение - использовать

get() = { Array<Int>(3){ nums[it] + 1 } }

Но это привело бы к созданию нового массива каждый раз, когда мне нужно получить доступ к преемнику. Есть ли простой, лучший способ?

Практический пример:

// Need to go from this...
private val _dayWiseEventsList =             // For internal use
        MediatorLiveData<List<Event>>()

val dayWiseEventsList: LiveData<List<Event>> // For immutable, external observation
        get() = _dayWiseEventsList


// ... to this
private val _dayWiseEventsListArray =        // For internal use
        Array<MediatorLiveData<List<Event>>>(DAYS) { MediatorLiveData() }

val dayWiseEventsListArray                   // For immutable, external observation
        // Need an alternative for this
        get() = Array<LiveData<List<Event>>>(DAYS) { _dayWiseEventsListArray[it] }

Ответы [ 4 ]

0 голосов
/ 01 февраля 2019
class NumsWithSuccessors {
    var nums: List<Int> = List(3){ 1 }
    val successors: List<Int> = object: AbstractList<Int>() {
        override val size get() = nums.size
        override fun get(index: Int) = nums[index] + 1;
    }
}

В приведенном выше примере successors - это виртуальный List, который фактически не содержит данных.Когда вы пытаетесь прочитать элемент из successors, он просто просматривает базовый список nums, чтобы вычислить значение.Класс AbstractList имеет дело с предоставлением реализаций для всего остального поведения списка на основе предоставленных вами реализаций get и size.

Это работает с List, но не с Array.Массив не может иметь пользовательское поведение;это примитивный тип данных, который просто хранит значения.List - это интерфейс, базовое поведение которого может быть изменено по желанию.

0 голосов
/ 01 февраля 2019

Вы можете лениво инициализировать его:

val successor by lazy { Array<Int>(3){ nums[it] + 1 } } 

Это создаст массив только один раз при первом обращении к нему, затем он вернет тот же массив при последующих обращениях.

Однако обратите вниманиечто это не будет обновлять successor в случае, если вы измените nums.Если вы хотите обновить его, вам нужно установить установщик клиента на nums и обновить successor соответственно.


Как я объяснил в комментариях, я бы сделал все это неизменным, например:

data class NumsWithSuccessors(val nums: List<Int> = List(3){ 1 }) {
    val successor by lazy { nums.map { it + 1 } }
}
0 голосов
/ 01 февраля 2019

Вы можете создать установщик для чисел и установить значение преемника внутри него, используя оператор map.Он не позволяет каждый раз создавать новый массив:

class NumsWithSuccessors {
    var successor: Array<Int> = arrayOf()
    var nums: Array<Int> = Array(3) { 1 }
    set(value) {
        field = value; successor = value.map { it + 1 }.toTypedArray()
    }
0 голосов
/ 01 февраля 2019

successor не может зависеть от nums, имеет модификатор val и одновременно использует кэшированный массив.Решение состоит в том, чтобы создавать новый список, используя функцию map каждый раз, когда к successor свойству обращаются:

class NumWithSuccessor {
    var nums = Array<Int>(3){ 1 }
    val successor
        get() = nums.map { it + 1 }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...