是否可以在Kotlin中将安全内联Optional设置为可选? [英] Is it possible to make safe inline Optional in Kotlin?
问题描述
有时在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:
Holder<T>?
whereHolder
isdata class Holder<out T>(val element: T)
- example1boolean
flag variable - example1containsKey
forMap<K, T?>
- example1- The special
UNINITIALIZED_VALUE
for representing the second kind ofnull
- 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屋!