Kotlin泛型函数和协方差

问题描述

我无法解决一个看似简单的问题。我有Reply类,它可以包含不同的响应类型-Views

interface View
data class NiceView(val name: String) : View

class MyReply<T : View>(view: T)

现在,我想编写一个接受命令并根据该命令返回适当视图的函数

fun <T : View> handle(command: Command): Reply<T> {
   return Reply(NiceView(""))
}

我可以在这里看到两个问题:

  1. 我在返回类型Reply<T>上遇到这个奇怪的错误,但这仅在此玩具示例中发生,而不在我的生产代码中发生:

    Type argument is not within its bounds.
    Expected: View
    Found: T
    
  2. 返回Reply()时出错。这是杀死我的大脑的东西,这就是我在生产代码中看到的东西:

    Type mismatch.
    required: T
    Found: NiceView
    Type mismatch.
    required: Reply<T>
    Found: Reply<NiceView>
    Type mismatch.
    required: View
    Found: NiceView
    

我确实尝试使用inout关键字弄乱协方差和对数,但无济于事。有人可以在这里指出正确的方向吗?

解决方法

我无法重现第一个问题,但只需将in modifier添加到Reply类的泛型参数或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修饰符表示 contravariance (类似于Java中的“?super T”)。

,

问题在于handle()表示T是泛型类型,它是View的子类。因此T可以是View任何子类,但是您试图将其强制为NiceView。这意味着这样的代码将不起作用:

val otherReply: Reply<OtherView> = handle(command)

handle试图返回NiceView,但是通用参数说它应该是OtherView

如果要保证函数始终返回Reply<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> {不是 表示“接受命令并返回适当视图”的函数。它的意思是“一个函数,它接受一种视图类型和一个命令,并返回该视图类型的答复。” handle caller 可以选择想要获取的View类型,这既不是您想要的类型,也不是您已经实现的类型,因为用户可能想要NiceView以外的内容。

给定您指定的目标,此代码中handle函数的适当类型是

fun handle(command: Command): Reply<*>