【问题标题】:Can a field be cast to non null version of itself?可以将字段转换为自身的非空版本吗?
【发布时间】:2017-07-11 01:18:05
【问题描述】:

我有一个数据类

data class MyModel(private val _data: MyData? = null)

我想确保我的数据只有在它不为空时才能访问,否则抛出。 我用下面这个很好。

    fun getData(): MyData {
        return checkNotNull(_data) { "data shouldn't be null" }
    }

但是,如果我按照Override getter for Kotlin data class 的指南进行操作,则以下投诉我需要返回MyData? 而不是MyData

val data = _data
    get(): MyData {
        return checkNotNull(field) { "data shouldn't be null" }
    }

field返回时是不是不能强制转换为它的Non-null版本?

【问题讨论】:

    标签: kotlin kotlin-null-safety


    【解决方案1】:

    如果您的目标是为返回AnyAny? 属性声明一个getter,这是不可能的。您将收到以下错误:

    Getter 返回类型必须与属性的类型相同

    所以尝试做类似的事情

    val test : String?
        get() : String = "hi"
    

    没有用。


    但是,您可以隐藏可空属性并公开一个通过强制转换引用可空值的不可空属性:

    private val test : String? = "hi"
    val testNotNull : String = test as String
    

    如果test 引用了null,则会抛出异常。

    例如:

    fun main(args: Array<String>) = print(Demo().testNotNull)
    
    class Demo(private var test: String? = "hi") {
        val testNotNull : String
    .       get() = test as String
    }
    

    您可以在try.kotlin.org 测试此代码段

    虽然这并不安全。你应该重新考虑你的设计。如果您不与 Java 进行互操作,则不应使用可空类型来惩罚自己。

    【讨论】:

    • 对于普通变量,这是可能的。对于字段,请尝试“字段作为字符串”,这没有帮助。作为一个类变量自定义 getter 进行测试,你会明白我的意思。
    • 嗨@Vince,那不是field。那只是从另一个变量转换到它。但这也是一个不错的技巧。也为你点赞:)
    • @Elye 那么这是不可能的,因为 getter 的类型必须与属性的类型匹配。如果该属性被定义(或在您的情况下,推断)为String?,它的getter 不能是String 类型。请问你为什么需要这个?这似乎不安全,有点代码味道。这可能是XY problem 的情况
    • 另外注意,如果你想抛出一个自定义错误,你可以使用类似val data get() = _data ?: throw MyException()
    【解决方案2】:

    我认为你不能。您对 fun getData() 所做的事情是 IMO 的有效方法。或者您显然不能使用数据类并创建一个普通类。

    我认为它可能适用于这样的事情:

    typealias notNullType = MyData
    
    data class Test(private val _value: MyData? = null) {
        val v: notNullType = _value as notNullType
        get() { return field }
    }
    

    这完全可以让你这样做:

    fun play() {
        val t = Test(null)
        print(t.v) //see what I did? :-)
    }
    

    这么说……我认为“隐藏”? 选项不一定是个好主意。

    【讨论】:

    • 不错的把戏。但即使只是val t=Test(null),它也会崩溃。也许在这种情况下,只需使用上面列出的fun getData() 方法回到基本状态。不过给你一个赞成票:)
    • 好吧,问题在于您试图隐藏字段为空的事实。这打破了它最初是? 的承诺,这反过来又为你提到的崩溃打开了大门。如果您想在 data 类中添加“自定义逻辑”,则必须添加它(您的 getData() 函数就是一个很好的例子),否则您会尝试覆盖编译器的检查机制,这就是 @987654330 @ 是为了……(同样,我不会);)
    • 我不打算隐藏“?”,但在访问它时如果它为空就让它崩溃,即checkNotNull(field) { "data shouldn't be null" }。如果不能访问,那还好,不要crash。
    【解决方案3】:

    如果你像MyData? 那样转换 MyData 类并不一定意味着它为 null

    '?' 只允许对象在实例中为空,它实际上变为空,以避免在运行时出现异常。

    你可以让你的类可以为空,它仍然可以包含你的数据。

    【讨论】:

    • 调用 getData() 的函数需要一个非空项。所以我们需要确保它不为空。我不想宣传 ?一直到调用者。我也不想用“!!”。
    • 啊,我明白我在手机上错过了那个抱歉
    猜你喜欢
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多