简体   繁体   English

即使支持字段可以为空,getter 也会返回不可为空的类型

[英]Having a getter return a non-nullable type even though the backing field is nullable

num should be nullable when set, but what it returns should always be non-nullable (have a default value). num设置时应该可以为空,但它返回的内容应该始终不可为空(具有默认值)。

class Test {
    var num: Int? = null
        get() = field ?: 5 // default value if null
}

The following does not compile even though the returned value is always non-null which makes sense to me, because the type is not inferred but taken from the backing field:即使返回值始终为非空,以下内容也不会编译,这对我来说很有意义,因为类型不是推断出来的,而是从支持字段中获取的:

val a: Int = Test().num

Type mismatch: inferred type is Int?类型不匹配:推断的类型是 Int? but Int was expected但 Int 是预期的

The question is how can I change the return type of that getter to be non-nullable?问题是如何将该 getter 的返回类型更改为不可为空? If I do so, the compiler says:如果我这样做,编译器会说:

Getter return type must be equal to the type of the property, ie 'Int?' Getter 返回类型必须等于属性的类型,即“Int?”


I know that I could solve it with another property numNotNullable (without a backing field).我知道我可以用另一个属性numNotNullable (没有支持字段)来解决它。

class Test {
    var num: Int? = null
        get() = field ?: 5 // default value if null

    val numNotNullable: Int
        get() = num ?: 5
}

val c: Int = Test().numNotNullable

But this is not what I want.但这不是我想要的。 Is there another way?还有其他方法吗?

var num: Int? = null

This is your property signature. 这是您的财产签名。 It doesn't matter, if you internally ensure that no null value is returned. 如果您在内部确保不返回null值,则无关紧要。 The signature says, that the value is nullable. 签名说,该值可以为空。

This implicates: 这意味着:

  • You are allowed to set null to this field 您可以将null设置为此字段
  • All classes using this field, must handle the fact that the property can return null 使用此字段的所有类必须处理属性可以返回null的事实

Your Solution with a second property is good. 第二个属性的解决方案很好。

You of course can replace the property with plain old java bean, but I wouldn't advise that, because than you have to access the prop with getNumb and setNum . 你当然可以用普通的旧java bean替换属性,但我不建议这样做,因为你必须使用getNumbsetNum访问prop。

class Test {
    private var num: Int = 5

    fun setNum(num: Int?) {
        this.num = num ?: 5
    }

    fun getNum() = num
}

I don't believe this is possible in Kotlin. 我不相信在Kotlin这是可能的。 You can't override the type of the the property for get/set. 您不能覆盖get / set属性的类型。 So if your property is an Int? 那么,如果您的房产是Int? you're going to have to return an Int? 你将不得不返回一个Int? and check if it is null when you use it. 并在使用它时检查它是否为null

There's technically a feature request for what you're looking for, but it's been years since it was made. 从技术上讲,这是一项针对您所寻找的功能的要求 ,但它已经创建了多年。

You can achive this using delegated properties您可以使用委托属性实现此目的

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class LazyVar<T : Any>(private var initializer: () -> T) : ReadWriteProperty<Any?, T> {
    private var value: T? = null

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        if (value == null) {
            value = initializer()
            print(value)
        }
        return value as T
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

class Test {
    var num: Int by LazyVar { 5 }
}

val a: Int = Test().num

Note, that this code is not thread-safe.请注意,此代码不是线程安全的。 Also with this code sample you can't set null value for you field (so no way back to default value).同样使用此代码示例,您无法为您的字段设置空值(因此无法返回默认值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM