键入通用密封类的安全使用

问题描述 投票:1回答:1

当我写通用密封类时,我发现了有趣的东西。这是第一个版本:

// 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>
}

第一个问题:FailureCancelled不使用T进/出位置,为什么这个演员没有被检查,我需要压制它?

过了一会儿,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

这个宣言就像一个魅力,现在我有问题:

第二个问题:为什么有必要在这里写out修饰符?

第三个问题:为什么Producer<Nothing>Producer<MyInterface>的亚型?协变的定义:Producer<A>Producer<B>的亚型,如果AB亚型,但Nothing不是MyInterface的亚型。它看起来像无证的extralinguistic功能。

generics kotlin covariance undocumented-behavior sealed-class
1个回答
1
投票

方差最终无法解决。 Response<MyInterfaceImpl>不是Response<MyInterface>因此不能使用FailureCancelled。虽然你没有使用泛型类型,但你仍然声明它。

out T时,你会在Java中产生类似? extends T的效果。

那么对于Nothing你有:

没有任何实例。您可以使用Nothing来表示“永不存在的值”。

这也意味着它是一切的子类型,因此也适用于泛型。

© www.soinside.com 2019 - 2024. All rights reserved.