【问题标题】:Checking for null variable and then making if statement on it检查空变量,然后对其进行 if 语句
【发布时间】:2019-12-18 03:24:35
【问题描述】:

我正在学习 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 岁,如果是,则将其设置为 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
            }
    }
}

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

Error:(19, 20) Kotlin: Operator call对应一个点限定 调用 '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?

【问题讨论】:

  • 当年龄为空时,你的二传手不会做任何事情。您可以在let 之后添加?: 以返回其他内容或引发错误。关于?.let 是否适合空检查,网上有一些争论。我认为let 在这种情况下是可以的,但可能有更好的解决方案。
  • 我已经更新了问题,以通话为例/

标签: kotlin


【解决方案1】:

?.let 是一个常见的 Kotlin 习惯用法,用于在使用成员属性时在检查空值后对变量执行某些操作,因为智能强制转换为非空值不适用于成员属性。但是您的总体设计存在更根本的问题。

如果年龄未知或未满 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,setter 不允许您更改 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 的值与您明确设置的值不匹配也就不足为奇了。

【讨论】:

    【解决方案2】:

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

    第二个是安全调用(?.) 功能。仅当调用对象为非 null 时,安全调用才会继续。

    只有当年龄不为空时才会调用你的设置器。

    Kotlin 语言设计者推荐该技术。以下 sn-p 来自 Kotlin in action 一书,第 6 章第 144 页

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

    【讨论】:

    • 感谢鼓励:)
    猜你喜欢
    • 2018-06-16
    • 2013-04-11
    • 2023-04-08
    • 1970-01-01
    • 2018-03-28
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    相关资源
    最近更新 更多