【问题标题】:Having a getter return a non-nullable type even though the backing field is nullable即使支持字段可以为空,让 getter 返回一个不可为空的类型
【发布时间】:2018-03-18 07:19:38
【问题描述】:

num 在设置时应该可以为空,但它返回的内容应该始终不可为空(具有默认值)。

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

即使返回的值始终为非空值,以下内容也无法编译,这对我来说很有意义,因为类型不是推断出来的,而是取自支持字段:

val a: Int = Test().num

类型不匹配:推断类型是 Int?但需要 Int

问题是如何将 getter 的返回类型更改为不可为空?如果我这样做,编译器会说:

Getter 返回类型必须等于属性的类型,即 '诠释?'


我知道我可以使用另一个属性 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

但这不是我想要的。 还有其他方法吗?

【问题讨论】:

  • 既然你知道它是安全的,你可以在技术上使用.num!!。这不是很好,但在这种情况下它仍然是安全的。
  • 您的支持属性解决方案绝对是正确的,它甚至是文档kotlinlang.org/docs/reference/…中支持属性的示例

标签: kotlin nullable getter non-nullable


【解决方案1】:

var num: Int? = null

这是您的财产签名。没关系,如果您在内部确保没有返回 null 值。签名说,该值可以为空。

这意味着:

  • 您可以将null设置为该字段
  • 使用该字段的所有类,必须处理属性可以返回null的事实

具有第二个属性的解决方案很好。

您当然可以用普通的旧 Java bean 替换该属性,但我不建议这样做,因为您必须使用 getNumbsetNum 访问该属性。

class Test {
    private var num: Int = 5

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

    fun getNum() = num
}

【讨论】:

    【解决方案2】:

    我不相信这在 Kotlin 中是可能的。您不能覆盖 get/set 的属性类型。因此,如果您的属性是Int?,您将不得不返回Int?,并在使用时检查它是否为null

    从技术上讲,feature request 是您正在寻找的东西,但它已经有好几年了。

    【讨论】:

      【解决方案3】:

      您可以使用 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
      

      请注意,此代码不是线程安全的。同样使用此代码示例,您无法为您的字段设置空值(因此无法恢复默认值)。

      【讨论】:

        猜你喜欢
        • 2020-09-16
        • 2010-10-10
        • 2020-09-05
        • 1970-01-01
        • 2023-02-18
        • 1970-01-01
        • 1970-01-01
        • 2021-12-09
        • 2015-06-26
        相关资源
        最近更新 更多