Как иметь пользовательский установщик с именованным аргументом и значением по умолчанию - PullRequest
0 голосов
/ 02 июля 2019

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

class ItemObject(var itemNumber: String = "",
             var itemQty: Int = 0)

Я могу использовать свойства этого класса без проблем itemObject.itemQty = itemObject.itemQty + 1 (доступ к как получателю, так и установщику).

Тем не менее, я бы хотел создать пользовательский установщик, чтобы элемент itemQty не опускался ниже нуля.Итак, я пробовал много вариантов на следующую тему:

class ItemObject(var itemNumber: String = "",
             itemQty: Int = 0) {

var itemQty: Int = 0
    set(value: Int) =
        if (value >= 0) {
            itemQty = value // Don't want to go negative
        } else {
        }

}

Это компилируется без проблем, но, похоже, по умолчанию itemQty по умолчанию равен нулю (или что-то вроде этого - у меня нет)не выследил его).

Кто-нибудь может указать мне правильное направление?Я, безусловно, ценю это - это мой первый проект Kotlin, и я мог бы немного помочь.:)

Ответы [ 3 ]

3 голосов
/ 02 июля 2019

Вот для чего vetoable:

var quantity: Int by Delegates.vetoable(0) { _, _, new ->
    new >= 0
}

Вернуть true, чтобы принять значение, вернуть false, чтобы отклонить его.

1 голос
/ 02 июля 2019

Итак, вы инициализируете действительное поле равным 0 и игнорируете переданное значение ... Вместо этого инициализируйте свойство с помощью переданного параметра конструктора:

  class Item(_itemQty: Int = 0) {
     var itemQty: Int = Math.max(0, _itemQty)
        set(v) { field = Math.max(0, v) }
  }

(я использовал два разных идентификатора для разделения параметра и свойства, как упоминалось в комментариях, вы также можете использовать одно и то же имя для свойства и параметра [но будьте осторожны, это может привести к путанице)).

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

Если установщик довольно сложный и его также необходимо применить к начальному значению, тогда вы можете инициализировать свойство и впоследствии запустить установщик с параметром:

  class Item(_itemQty: Int = 0) {
     var itemQty: Int = 0
        set(v) { field = Math.max(0, v) }

     init { itemQty = _itemQty }
  }

В качестве примечания, основанного на мнении, item.itemQty не является действительно описательным, item.quantity было бы намного более читабельным.

0 голосов
/ 02 июля 2019

Существуют различные способы предотвращения падения значения ниже нуля. Один из них без знака типов. Экспериментальный на данный момент. UInt в вашем случае

class ItemObject(var itemNumber: String = "",
                 var itemQty: UInt = 0u
)

Если вас не волнует переполнение значения - это может быть опция

Другим способом является делегирование собственности

class ItemObject(var itemNumber: String = "", itemQty: Int = 0) {
    var itemQty: Int by PositiveDelegate(itemQty)
}

class PositiveDelegate(private var prop: Int) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = prop

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
        if (value >= 0) prop = value
    }
}

Третий с пользовательскими установщиками описан в других ответах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...