generics - 通用密封类的类型安全使用
问题描述
当我编写通用密封类时,我发现了有趣的事情。这是第一个版本:
// 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>
}
第一个问题:
Failure
并且Cancelled
不T
用于进/出位置,为什么这个演员没有被检查,我需要压制它?
过了一会儿,康斯坦丁向我展示了如何声明类型安全的密封类的解决方案:
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>
if的子类型的A
子类型B
,但Nothing
不是 的子类型MyInterface
。它看起来像未记录的语言外功能。
解决方案
差异最终无法解决。Response<MyInterfaceImpl>
不是Response<MyInterface>
,因此Failure
也Cancelled
不能使用。即使您没有使用通用类型,您仍然可以声明它。
放置时out T
,您将获得类似Java? extends T
的效果。
那么Nothing
你有:
没有什么是没有实例的。您可以使用 Nothing 来表示“一个从不存在的值”。
这也意味着它是所有事物的子类型,因此也适用于泛型。
推荐阅读
- laravel - Laravel 不等于不按预期工作
- pine-script - 如何在 pinescript 中制作多个时间框架 ichimoku 指标?
- reactjs - React JS APP中如何管理多个角色?
- c# - SQL Uniqueidentifier 和 hashbytes 与 c# 不匹配
- java - 带空格的 Java 格式数字
- python - 是否有统计测试来检查python中组之间的变异系数(相对标准偏差)的差异?
- node.js - ansi-html 中不受控制的资源消耗
- hive - 在 Hive 3.1.3 中将时间戳从 ms 转换为字符串格式
- python - 在 Pandas 的列中替换多个字符串值的更快方法
- spring-boot - 从 Spring Boot 低版本迁移到高版本后 @Valid 的编译错误