是否可以在Kotlin中将安全内联Optional设置为可选? [英] Is it possible to make safe inline Optional in Kotlin?

查看:63
本文介绍了是否可以在Kotlin中将安全内联Optional设置为可选?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时在Kotlin中,我必须使用双重可空性.例如,当我想使用 T?时,我需要双重可空性,其中 T 可能是可为空的类型.有几种方法可以做到这一点:

In Kotlin sometimes I have to work with double nullability. For example, I need double nullability, when I want to use T? where T may be a nullable type. There are a few approaches for doing this:

  1. Holder< T>?,其中 Holder 数据类Holder< out T>(val元素:T)-示例 1
  2. containsKey for Map< K,T?> -
  1. Holder<T>? where Holder is data class Holder<out T>(val element: T) - example1
  2. boolean flag variable - example1
  3. containsKey for Map<K, T?> - example1
  4. The special UNINITIALIZED_VALUE for representing the second kind of null - example1

最后一种方法具有最佳性能,但也最容易出错.因此,我决定将其封装在内联类Optional< T> 中:

The last approach has the best performance, but it's also the most error-prone. So I've decided to encapsulate it in inline class Optional<T>:

inline class Optional<out T> @Deprecated(
    message = "Not type-safe, use factory method",
    replaceWith = ReplaceWith("Optional.of(_value)")
) constructor(private val _value: Any?) {
    val value: T?
        get() =
            @Suppress("UNCHECKED_CAST")
            if (isPresent) _value as T
            else null

    val isPresent: Boolean
        get() = _value != NULL

    companion object {
        @Suppress("DEPRECATION")
        fun <T> of(value: T) = Optional<T>(value)

        fun <T : Any> ofNullable(value: T?): Optional<T> =
            if (value == null) EMPTY
            else of(value)

        @Suppress("DEPRECATION")
        val EMPTY = Optional<Nothing>(NULL)
    }

    private object NULL
}

inline fun <T> Optional<T>.ifPresent(code: (T) -> Unit) {
    @Suppress("UNCHECKED_CAST")
    if (isPresent) return code(value as T)
}

inline fun <T> Optional<T>.or(code: () -> T): T {
    ifPresent { return it }
    return code()
}

Optional 的第一个问题是 public构造函数,它允许创建参数不匹配类型的实例.

The first problem with this Optional is public constructor, which allows creating instances with arguments of not matching type.

第二个问题是在测试时发现的.这是失败的测试:

The second problem was noticed at testing time. Here is the failed test:

emptyOr { Optional.EMPTY }.value assertEql null

fun <T> emptyOr(other: () -> T): T = Optional.EMPTY.or(other)

例外:

Exception ClassCastException: Optional$NULL cannot be cast to Optional
    at (Optional.kt:42) // emptyOr { Optional.EMPTY }.value assertEql null

如果从 Optional 中删除 inline 修饰符,则测试将通过.

If I remove inline modifier from Optional, the test will pass.

:有什么方法可以解决这些问题,而无需从 Optional 删除 inline 修饰符?

Q: Is there any way to fix these problems without removing inline modifier from Optional?

1 示例包括一些上下文.在撰写我添加了错误链接之前,请完整阅读它们.

1 Examples include some context. Please read them fully before writing that I added incorrect links.

推荐答案

我在我的一个项目中实现了完全相同的实用程序:

I implemented exactly the same utility in one of my projects: OptionalValue.kt. My implementation is very similar to yours, it is also an inline/value class, so it should be cpu/memory efficient and it passes all tests I throw at it.

关于您的第一个问题:关于公共构造函数.有专门针对这种情况的注释: @PublishedApi .我试图从您的示例中重现ClassCastException,但是它对我没有问题,因此我认为这是Kotlin本身的错误(?).

Regarding your first question: about a public constructor. There is an annotation specifically for this case: @PublishedApi. I tried to reproduce ClassCastException from your example, but it worked for me without problems, so I believe it was a bug in Kotlin itself (?).

此外,为了回答为什么我们需要双重可空性的问题,我解释了我的观点

Also, to answer the question why do we need double nullability, I explained my point here

这篇关于是否可以在Kotlin中将安全内联Optional设置为可选?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆