我想要一个等同于Java Optional但又
的类非工作代码:
class MutableOptional<T> {
private var value: T? = null
private var isSet: Boolean = false
fun set(value: T)
{
this.value = value
isSet = true
}
fun unset()
{
isSet = false
value = null
}
fun get(): T
{
if (!isSet) {
throw Error("Value not set")
}
return value!! // <<< NPE here
}
}
fun f()
{
val opt = MutableOptional<Int?>()
opt.set(null)
assertNull(opt.get())
}
问题在于,如果我尝试设置null,则get()调用将失败并返回空指针异常(由!!运算符引起)。
一些不起作用的提案:
注意:这个例子是合成的,我真的不需要mutable可选,它只是一个简单易懂的例子,说明了偶尔遇到的Kotlin泛型和null安全问题。找到这个特定示例的解决方案将有助于解决许多类似的问题。实际上我有这个类的不可变版本的解决方案,但它涉及为当前和非现在值创建接口和两个实现类。这种不可变的可选项可以用作&#34;值&#34;的类型。成员,但我认为这是一个相当大的开销(也考虑到每个set()的包装对象创建)只是为了克服语言限制。
答案 0 :(得分:6)
编译器希望您编写对所有可能的T
都是类型安全的代码,可以是nullable和not-null(除非您为type参数指定了非null的上限,例如{{ 1}},但这不是你需要的。)
如果将T : Any
存储在属性中,则在非空类型参数的情况下,它与T?
的类型不同,因此不允许使用T
和{{ 1}}可互换。
但是,制作unchecked cast可以绕过限制并将T
值作为T?
返回。与非空断言(T?
)不同,演员在运行时不会被检查,并且在遇到T
时不会失败。
更改!!
功能,如下所示:
null
答案 1 :(得分:0)
我遇到了类似的问题。我的用例是在反序列化JSON对象时区分null和undefined值。因此,我创建了一个能够处理空值的不可变Optional。在这里,我分享我的解决方案:
interface Optional<out T> {
fun isDefined(): Boolean
fun isUndefined(): Boolean
fun get(): T
fun ifDefined(consumer: (T) -> Unit)
class Defined<out T>(private val value: T) : Optional<T> {
override fun isDefined() = true
override fun isUndefined() = false
override fun get() = this.value
override fun ifDefined(consumer: (T) -> Unit) = consumer(this.value)
}
object Undefined : Optional<Nothing> {
override fun isDefined() = false
override fun isUndefined() = true
override fun get() = throw NoSuchElementException("No value defined")
override fun ifDefined(consumer: (Nothing) -> Unit) {}
}
}
fun <T> Optional<T>.orElse(other: T): T = if (this.isDefined()) this.get() else other
诀窍:必须将orElse方法定义为不破坏协方差的扩展,因为Kotlin does not support lower bound for now。
然后,我们可以通过以下方式定义不强制转换的MutableOptional:
class MutableOptional<T> {
private var value: Optional<T> = Optional.Undefined
fun get() = value.get()
fun set(value: T) { this.value = Optional.Defined(value) }
fun unset() { this.value = Optional.Undefined }
}
我对我一成不变的Optional实现感到满意。但是我对MutableOptional不太满意:我不喜欢以前基于投射的解决方案(我不喜欢投射)。但是我的解决方案会产生不必要的装箱,这可能更糟...