Kotlin 泛型函数和逆变
Kotlin generic functions and contravariance
我无法解决一个看似简单的问题。我有 Reply
class,它可以包含不同的响应类型 - Views
:
interface View
data class NiceView(val name: String) : View
class MyReply<T : View>(view: T)
现在,我想编写一个接受命令的函数,并return根据命令生成适当的视图:
fun <T : View> handle(command: Command): Reply<T> {
return Reply(NiceView(""))
}
我在这里看到两个问题:
我在 return 类型 Reply<T>
上遇到了这个奇怪的错误,但这只发生在这个玩具示例中,而不是我的生产代码中:
Type argument is not within its bounds.
Expected: View
Found: T
returning Reply()
时出错。这是杀死我大脑的东西,这是我在生产代码中看到的:
Type mismatch.
Required: T
Found: NiceView
Type mismatch.
Required: Reply<T>
Found: Reply<NiceView>
Type mismatch.
Required: View
Found: NiceView
我确实尝试使用 in
和 out
关键字搞乱协变和逆变,但无济于事。有人可以在这里为我指明正确的方向吗?
我无法重现第一个问题,但可以通过简单地在 Reply
class 或 return 的通用参数中添加 in
modifier 来解决第二个问题handle
函数的值:
interface View
data class NiceView(val name: String) : View
class Reply<in T : View>(view: T)
fun <T : View> handle(command: Command): Reply<T> {
return Reply(NiceView(""))
}
// OR
class Reply<T : View>(view: T)
fun <T : View> handle(command: Command): Reply<in T> {
return Reply(NiceView(""))
}
in
修饰符表示逆变(类似于Java中的“?super T”)。
问题是 handle()
是说 T
是一个通用类型,它是 View
的子类。所以 T
可以是 View
的 任何 子类,但你试图强制它成为 NiceView
。这意味着像这样的代码将不起作用:
val otherReply: Reply<OtherView> = handle(command)
handle
试图 return NiceView
,但通用参数说它应该是 OtherView
.
如果你想保证你的函数总是returnReply<T : View>
,你需要构造一个泛型类型的实例T
。这意味着您必须以某种方式识别 View
实现。我不知道您的其余代码是什么样的,但这是一个接受 view
作为参数的示例:
fun <T : View> handle(command: Command, view: T): Reply<T> {
return Reply(view)
}
fun main() {
val otherReply: Reply<OtherView> = handle(command, OtherView(""))
}
或者如果你不关心允许调用者指定视图类型,你根本不需要泛型参数:
fun handle(command: Command): Reply<View> {
return Reply(NiceView(""))
}
fun <T : View> handle(command: Command): Reply<T> {
不是 表示“接受命令和returns 适当视图”的功能。它的意思是“接受一种视图类型的函数——和一个命令——以及 returns 对该类型视图的回复。” handle
的 caller 可以选择它想要获得的 View
的任何类型,这不是你想要的——也不是你已经实现的,因为用户可能想要 NiceView
.
以外的东西
根据您的既定目标,此代码中 handle
函数的适当类型是
fun handle(command: Command): Reply<*>
我无法解决一个看似简单的问题。我有 Reply
class,它可以包含不同的响应类型 - Views
:
interface View
data class NiceView(val name: String) : View
class MyReply<T : View>(view: T)
现在,我想编写一个接受命令的函数,并return根据命令生成适当的视图:
fun <T : View> handle(command: Command): Reply<T> {
return Reply(NiceView(""))
}
我在这里看到两个问题:
我在 return 类型
Reply<T>
上遇到了这个奇怪的错误,但这只发生在这个玩具示例中,而不是我的生产代码中:Type argument is not within its bounds. Expected: View Found: T
returning
Reply()
时出错。这是杀死我大脑的东西,这是我在生产代码中看到的:Type mismatch. Required: T Found: NiceView Type mismatch. Required: Reply<T> Found: Reply<NiceView> Type mismatch. Required: View Found: NiceView
我确实尝试使用 in
和 out
关键字搞乱协变和逆变,但无济于事。有人可以在这里为我指明正确的方向吗?
我无法重现第一个问题,但可以通过简单地在 Reply
class 或 return 的通用参数中添加 in
modifier 来解决第二个问题handle
函数的值:
interface View
data class NiceView(val name: String) : View
class Reply<in T : View>(view: T)
fun <T : View> handle(command: Command): Reply<T> {
return Reply(NiceView(""))
}
// OR
class Reply<T : View>(view: T)
fun <T : View> handle(command: Command): Reply<in T> {
return Reply(NiceView(""))
}
in
修饰符表示逆变(类似于Java中的“?super T”)。
问题是 handle()
是说 T
是一个通用类型,它是 View
的子类。所以 T
可以是 View
的 任何 子类,但你试图强制它成为 NiceView
。这意味着像这样的代码将不起作用:
val otherReply: Reply<OtherView> = handle(command)
handle
试图 return NiceView
,但通用参数说它应该是 OtherView
.
如果你想保证你的函数总是returnReply<T : View>
,你需要构造一个泛型类型的实例T
。这意味着您必须以某种方式识别 View
实现。我不知道您的其余代码是什么样的,但这是一个接受 view
作为参数的示例:
fun <T : View> handle(command: Command, view: T): Reply<T> {
return Reply(view)
}
fun main() {
val otherReply: Reply<OtherView> = handle(command, OtherView(""))
}
或者如果你不关心允许调用者指定视图类型,你根本不需要泛型参数:
fun handle(command: Command): Reply<View> {
return Reply(NiceView(""))
}
fun <T : View> handle(command: Command): Reply<T> {
不是 表示“接受命令和returns 适当视图”的功能。它的意思是“接受一种视图类型的函数——和一个命令——以及 returns 对该类型视图的回复。” handle
的 caller 可以选择它想要获得的 View
的任何类型,这不是你想要的——也不是你已经实现的,因为用户可能想要 NiceView
.
根据您的既定目标,此代码中 handle
函数的适当类型是
fun handle(command: Command): Reply<*>