generics - 通用密封类的类型安全使用

标签 generics kotlin covariance undocumented-behavior sealed-class

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

// 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 and Cancelled isn't use T 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 of Producer<MyInterface>? By definition of covariant: Producer<A> is subtype of Producer<B> if A subtype of B, but Nothing isn't subtype of MyInterface. It looks like undocumented extralinguistic feature.

最佳答案

差异最终没有解决。 Response<MyInterfaceImpl>不是Response<MyInterface>因此FailureCancelled不能使用。即使您没有使用通用类型,您仍然可以声明它。

放置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/

相关文章:

java - java中的自定义通用集合Trim类

android - 如何在分页库的PagedList中添加Item

c# - T 必须逆变有效

java - 使用方法引用和原始类型进行类型推断

java - 与 Java 相比,Scala 对于泛型和通配符有哪些机制?

java - 使用泛型的工厂对象创建者

android - 将回调 hell 转换为延迟对象

java - Google Play服务游戏signInSilently()失败错误 'com.google.android.gms.common.api.ApiException: 4: 4 '

Java协变/逆变与add/get

python - 如何从 3d numpy 数组中提取向量?