当我编写通用密封类时,我发现了有趣的事情。这是第一个版本:
// sample interface and implementation
interface MyInterface
class MyInterfaceImpl : MyInterface
sealed class Response<T: MyInterface>
data class Success<T: MyInterface>(val payload: T) : Response<T>()
data class Failure(val errorCode: Int) : Response<MyInterface>()
object Cancelled : Response<MyInterface>()
假设我们还有这样的请求函数:
fun <T: MyInterface> requestObject(cls : KClass<T>): Response<T> = TODO("Request")
现在在使用方面我们遇到了错误:
fun test() = when (val response = requestObject(MyInterfaceImpl::class)) {
is Success -> print("Payload is ${response.payload}") // Smart cast perfectly works!
is Failure -> print("Error code ${response.errorCode}") // Incomparable types: Failure and Response<MyInterfaceImpl>
Cancelled -> print("Request cancelled") // Incomparable types: Cancelled and Response<MyInterfaceImpl>
}
First question:
Failure
andCancelled
isn't useT
for in/out positions, why this cast is unchecked and I need to suppress it?
过了一会儿,Konstantin向我展示如何声明类型安全密封类的解决方案:
sealed class Response<out T: MyInterface> // <-- out modifier here
data class Success<T: MyInterface>(val payload: T) : Response<T>()
data class Failure(val errorCode: Int) : Response<Nothing>() // <-- Nothing as type argument
object Cancelled : Response<Nothing>() // <-- Nothing as type argument
这个声明就像一个魅力,现在我有疑问:
Second question: why it's necessary to write
out
modifier here?Third question: why
Producer<Nothing>
is subtype ofProducer<MyInterface>
? By definition of covariant:Producer<A>
is subtype ofProducer<B>
ifA
subtype ofB
, butNothing
isn't subtype ofMyInterface
. It looks like undocumented extralinguistic feature.
最佳答案
差异最终没有解决。 Response<MyInterfaceImpl>
不是Response<MyInterface>
因此Failure
和Cancelled
不能使用。即使您没有使用通用类型,您仍然可以声明它。
放置out T
时,你会得到类似 ? extends T
的效果在Java中。
然后是 Nothing
你有:
Nothing has no instances. You can use Nothing to represent "a value that never exists".
这也意味着它是所有事物的子类型,因此也适用于泛型。
关于generics - 通用密封类的类型安全使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54804289/