问题
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
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()
}
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:
Exception ClassCastException: Optional$NULL cannot be cast to Optional
at (Optional.kt:42) // emptyOr { Optional.EMPTY }.value assertEql null
If I remove inline
modifier from Optional
, the test will pass.
Q: Is there any way to fix these problems without removing inline
modifier from Optional
?
1 Examples include some context. Please read them fully before writing that I added incorrect links.
来源:https://stackoverflow.com/questions/58256697/is-it-possible-to-make-safe-inline-optional-in-kotlin