检查空变量,然后在其上执行if语句

时间:2019-12-17 15:19:02

标签: kotlin

我正在学习科特林。我想知道这是解决此问题的最佳方法: 我有一堂简单的课:

class AlternativeCustomerTwo(
    val name: String = "Name Not Provided",
    var age: Int? = null,
    var address: String = "Address not provided"
) 

它具有默认参数,并且可以为空。

我要包含以下字段:

var isApproved: Boolean = false

所以现在我有一个看起来像这样的类:

class AlternativeCustomerTwo(
    val name: String = "Name Not Provided",
    var age: Int? = null,
    var address: String = "Address not provided"
) {

   var isApproved: Boolean = false}

现在,我想覆盖isApproved的默认设置器,该设置器检查年龄是否超过21岁,如果超过21岁,则将其设置为true。像这样:

class AlternativeCustomerTwo(
    val name: String = "Name Not Provided",
    var age: Int? = null,
    var address: String = "Address not provided"
) { 
 var isApproved: Boolean = false
    set(value) {
            if(age >= 21) {
                field = value
            }
    }
}

这里的问题是年龄。代码无法编译,这是错误:

  

错误:(19,20)Kotlin:操作员呼叫与点限定符相对应   调用“ age.compareTo(21)”,这是可为空的接收器所不允许的   “年龄”。

经过修补后,我实现了所需的功能,如下所示:

class AlternativeCustomerTwo(
    val name: String = "Name Not Provided",
    var age: Int? = null,
    var address: String = "Address not provided"
) {

   var isApproved: Boolean = false
    set(value) {
       age?.let {
           if(it >= 21) {
               field = value
           }
       }
    }
}

如果我这样称呼它:

val customer = AlternativeCustomerTwo(name = "John", age = 120)
customer.isApproved = true

然后打印:true

或者

val customer = AlternativeCustomerTwo(name = "John", age = 12)
    customer.isApproved = true

打印错误 我的问题是,这是正确的方法,还是我正在做一些可怕的Kotlin?

2 个答案:

答案 0 :(得分:1)

?.let是常见的Kotlin习惯用法,用于在使用成员属性时在进行空检查之后对变量进行操作,因为智能广播到非null不适用于成员属性。但是您的总体设计还有一个更根本的问题。

如果年龄不明或未满21岁,isApproved的设置者将否决更改。我可以想到多种情况,这些情况会造成难以发现的错误。这是一个示例:

val tinyTim = AlternativeCustomerTwo("Tiny Tim", 30)
tinyTim.isApproved = true

// Oops, the age is actually 3. Let's correct it.
tinyTim.age = 3
tinyTim.isApproved = false

他仍将获得批准,因为如果年龄不超过21岁,二传手将不允许您更改isApproved

这是另一个例子。

val john = AlternativeCustomerTwo("John").apply {
    isApproved = true
    age = 45
}

由于我们以错误的顺序设置属性,因此即使我们希望他被批准,也不会被批准。

一种解决方案是使用自定义getter而不是自定义setter:

var isApproved: Boolean = false
    get(value) = field && (age?.let { it >= 21 } ?: false)

然后您可以在设置某人的正确年龄之前将其标记为已批准,并且如果该人的年龄已更新,则返回的value也将是正确的。但是,为绝对清晰起见,我建议使用两个属性:

var isApproved = false
val isAllowed: Boolean
    get() = isApproved && (age?.let { it >= 21 } ?: false)

然后,isApproved的值与您明确设置的值不匹配就不会感到惊讶。

答案 1 :(得分:0)

您正在使用Kotlin的两个非常好的语言功能。 首先是let函数。它是一个作用域函数,它接受其调用对象(在您的情况下为 age )并将其作为lambda的参数(在您的情况下为 it )。

second是安全呼叫(?。)功能。仅当调用对象为非null时,安全调用才会继续。

因此,只有在age不为null时,才会调用您的setter。

此技术是Kotlin语言设计师推荐的。以下摘录摘自《行动中的科特林》一书,第6章,第144页

  

您可以使用let函数,并通过安全调用来调用它。所有让   函数所做的是将调用它的对象转换为参数   的lambda。如果将其与安全调用语法结合使用,   有效地转换您可以调用的可为空类型的对象   设为非空类型