为什么 Kotlin 不能在接口和派生自它的泛型类型之间进行智能转换?
Why can't Kotlin smart cast between an interface and the generic type that is derived from it?
我有以下 class:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): I {
return object : ViewIntent{} // type mismatch on this line
}
}
我收到预编译错误指出:
Type mismatch
Required: I
Found: <S, I>
为了修复这个预编译错误,我将 ViewIntent 对象转换为 I:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): I {
@Suppress("UNCHECKED_CAST")
return object : ViewIntent{} as I
}
}
但为什么 Kotlin 不能检测到 I
必须派生自 ViewIntent
并进行智能转换?
只是因为 "I" 不一定派生自 ViewIntent,而恰恰是 ViewIntent class。
你可以这样修复:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): ViewIntent {
return object : ViewIntent{}
}
}
按你的方式做真的很不安全。
要了解原因,我想您应该开始阅读以下内容:
https://blog.kotlin-academy.com/kotlin-generics-variance-modifiers-36b82c7caa39
https://kotlinlang.org/docs/reference/generics.html
https://proandroiddev.com/understanding-generics-and-variance-in-kotlin-714c14564c47
那是因为 ViewIntent
不是 I
。参见示例:
class MyViewIntent : ViewIntent
class MyPresenterActivity : PresenterActivity<..., MyViewIntent>() {
// inherited from PresenterActivity
open fun initViewIntent(): ViewIntent {
return object : ViewIntent{} as MyViewIntent // you see where this breaks
}
}
基本上,您所做的事情不起作用的原因是因为 I
是 ViewIntent
的子 class。你的对象也是一个subclassViewIntent
。这是一个完全不同的subclass。您正在执行的转换就像尝试将 StringBuilder
转换为 String
.
现在让我们讨论一下我认为您 "want" 应该做什么以及为什么这也不起作用。为了真正得到你想要的结果,你需要直接创建I
类型,像这样:
return object : I {}
我们用实际的 class、
替换了 I
return object : SomeClass {}
这肯定也会失败。 SomeClass
的构造函数需要被调用,而你没有这样做。在使用泛型类型时,无法知道将什么传递给该构造函数。
我有以下 class:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): I {
return object : ViewIntent{} // type mismatch on this line
}
}
我收到预编译错误指出:
Type mismatch
Required: I
Found: <S, I>
为了修复这个预编译错误,我将 ViewIntent 对象转换为 I:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): I {
@Suppress("UNCHECKED_CAST")
return object : ViewIntent{} as I
}
}
但为什么 Kotlin 不能检测到 I
必须派生自 ViewIntent
并进行智能转换?
只是因为 "I" 不一定派生自 ViewIntent,而恰恰是 ViewIntent class。
你可以这样修复:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): ViewIntent {
return object : ViewIntent{}
}
}
按你的方式做真的很不安全。
要了解原因,我想您应该开始阅读以下内容:
https://blog.kotlin-academy.com/kotlin-generics-variance-modifiers-36b82c7caa39
https://kotlinlang.org/docs/reference/generics.html
https://proandroiddev.com/understanding-generics-and-variance-in-kotlin-714c14564c47
那是因为 ViewIntent
不是 I
。参见示例:
class MyViewIntent : ViewIntent
class MyPresenterActivity : PresenterActivity<..., MyViewIntent>() {
// inherited from PresenterActivity
open fun initViewIntent(): ViewIntent {
return object : ViewIntent{} as MyViewIntent // you see where this breaks
}
}
基本上,您所做的事情不起作用的原因是因为 I
是 ViewIntent
的子 class。你的对象也是一个subclassViewIntent
。这是一个完全不同的subclass。您正在执行的转换就像尝试将 StringBuilder
转换为 String
.
现在让我们讨论一下我认为您 "want" 应该做什么以及为什么这也不起作用。为了真正得到你想要的结果,你需要直接创建I
类型,像这样:
return object : I {}
我们用实际的 class、
替换了I
return object : SomeClass {}
这肯定也会失败。 SomeClass
的构造函数需要被调用,而你没有这样做。在使用泛型类型时,无法知道将什么传递给该构造函数。