我正在学习科特林。我想知道这是解决此问题的最佳方法: 我有一堂简单的课:
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?
答案 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。如果将其与安全调用语法结合使用, 有效地转换您可以调用的可为空类型的对象 设为非空类型