如何使用带有命名参数和默认值的自定义设置器

时间:2019-07-01 21:22:57

标签: kotlin

我有一个带有命名参数的Kotlin类,未指定参数的默认值。我正在尝试找出如何为一个参数创建自定义设置器的方法,尽管似乎很简单,但似乎无法弄清楚我在做什么错。这是该类的简化版本:

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

我可以使用此类的属性,而不会出现itemObject.itemQty = itemObject.itemQty + 1(同时访问getter和setter)。

但是,我想创建一个自定义设置器,以防止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 个答案:

答案 0 :(得分:3)

vetoable的用途是

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

返回true接受该值,返回false拒绝该值。

答案 1 :(得分:1)

好吧,您将实数字段初始化为0并忽略了传递的值...而是使用传递的构造函数参数初始化属性:

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

(我使用了两个不同的标识符来分隔参数和属性,如注释中所述,您也可以为属性和参数使用相同的名称[但请注意,这可能会增加混乱))。

您还应该设置backing field,而不是设置器本身,否则设置器将无休止地递归。

如果设置器非常复杂,并且还需要将其应用于初始值,则可以初始化属性,然后使用参数执行设置器:

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

     init { itemQty = _itemQty }
  }

作为基于意见的附带说明,item.itemQty并不是真正的描述性内容,item.quantity更具可读性。

答案 2 :(得分:0)

有多种防止值低于零的方法。 一种是无符号类型。目前处于实验阶段。 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
    }
}

第三种带有自定义设置器的方法在其他答案中有所描述。