Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin-有用性;计算的;var属性?_Kotlin - Fatal编程技术网

Kotlin-有用性;计算的;var属性?

Kotlin-有用性;计算的;var属性?,kotlin,Kotlin,我注意到,当我有一个var属性和一个自定义get,它不使用字段标识符时,仍然会生成一个支持字段。我检查了字节码,文档也这么说: 如果属性使用 至少一个访问器的默认实现,或者 自定义访问器通过字段标识符引用它。 (重点是我的) 考虑这样一个类。由于它是一个var属性,因此将生成一个默认的set(以及一个支持字段): class Banana { var ripeness = 1 var color: String = "green" get() = when {

我注意到,当我有一个
var
属性和一个自定义
get
,它不使用
字段
标识符时,仍然会生成一个支持字段。我检查了字节码,文档也这么说:

如果属性使用 至少一个访问器的默认实现,或者 自定义访问器通过字段标识符引用它。
(重点是我的)

考虑这样一个类。由于它是一个
var
属性,因此将生成一个默认的
set
(以及一个支持字段):

class Banana {
    var ripeness = 1

    var color: String = "green"
        get() = when {
            ripeness > 80 -> "brown"
            ripeness > 50 -> "yellow"
            else -> "green"
        }
}

val b = Banana()
b.color = "blue"

println(b.color)
但是,
println
将始终打印“绿色”,无论我将
颜色设置为什么。无论如何,支持字段都将设置为“蓝色”。
由于在访问器方法之外(或通过反射)无法访问它,我真的想不出这样做的原因。
我是不是遗漏了什么?可能是一个用例或另一种访问支持字段的方式?或者它只是一个bug(或者IntelliJ中缺少警告)?

带有未使用备份字段的“计算的”
var
属性应该是“计算的”
val
属性

如果您不打算在示例中使用backing字段,那么
Banana.color
不应该是
var
而是
val
。e、 g:

class Banana {
    var ripeness = 1

    val color: String
        get() = when {
            ripeness > 80 -> "brown"
            ripeness > 50 -> "yellow"
            else -> "green"
        }
}
另一方面,如果您确实希望在某些情况下使“computed”属性可重写,那么您需要实际使用backing字段。e、 g:

class Banana {
    var ripeness = 1

    var color: String = "green"
        get() = when {
            ripeness > 80 -> "brown"
            ripeness > 50 -> "yellow"
            else -> field
        }
}
当心瓦尔。。。get(),其行为可能会非常令人惊讶:

class Val {
    val millis: Long = System.currentTimeMillis()
}
class ValGet {
    val millis: Long
        get() = System.currentTimeMillis()
}

val v = Val()
val g = ValGet()
for(i in 0..4) {
    println("val:" +  v.millis + " valget:"+g.millis)
    Thread.sleep(7)
}

如果一个
val x:Int
在引用两次时不能被依赖为相同,那么
val
有什么用处?显然,如果父级足够开放,它甚至可以用于覆盖,
抽象val looksQuiteLikeImmutable:Int
可能会产生误导。感觉又像是超级棒了。。。(至少这是我在1.4.21中观察到的)

用例是您可能希望在自定义getter中使用backing字段。不这样做会使支持字段变得无用。我认为这应该给编译器一个警告。@marstran是的,我同意这个警告。这是一个边缘案例,但您可以很快遇到它,所以我认为可能还有更多。是的,我知道我应该声明它
val
。我只是认为这是一个陷阱,特别是初学者可能很容易遇到,因此我认为可能有一个很好的理由允许它。嗯,
millis
对象的属性,
val
表示对象的用户不能更改它。但是用户不应该期望它不会改变。然而,在这种特殊情况下,函数可能比属性更有意义,因为系统毫不是任何对象的属性。。。除了系统……这可能会产生误导,因为对于新手来说,
val-somthing:Int
显然不像描述函数返回类型。
get()
实际上成为了类型的一部分,但惯例将其放在单独的一行上,并且在第一行上没有任何表示类型尚未完全指定的指示。在我看来,这绝对是一个“小心”的陷阱。像IntelliJ这样的工具(他们应该知道关于kotlin的一两件事)在使用站点上呈现的都是相同的(包括Java
final long某物的实际等价物;
,默认构造函数中定义的val)。