Scala:无法使用超类型声明对函数的引用

时间:2013-09-05 21:51:47

标签: scala compiler-errors

为noob问题道歉,但我对Scala很新。

我有以下Scala类:

class Test {
    class Request {def getValue(): String = {"request"}}
    class Response {def getValue(): String = {"response"}}
    case class MyRequest(message: String) extends Request
    case class MyResponse(message: String) extends Response
    val myFunction: (Request) => Response = doSomething
    private val functions = scala.collection.mutable.Map[String, (Request) => Response](
        "myFunction" -> myFunction
    )
    def doSomething(request: MyRequest): MyResponse = {
        null
    }
}

无法使用以下错误进行编译:

type mismatch;
 found   : Test.this.MyRequest => Test.this.MyResponse
 required: Test.this.Request => Test.this.Response
    val myFunction: (Request) => Response = doSomething

如果我将myFunction的声明和函数更改为:

,它会起作用
val myFunction: (MyRequest) => MyResponse = doSomething
private val functions = scala.collection.mutable.Map[String, (MyRequest) => MyResponse](
    "myFunction" -> myFunction
)

但这不是我想要的 - 我希望能够将具有不同具体类型(所有扩展请求或响应)的其他功能添加到地图中。所以我想将地图声明为采用Request或Response的任何子类。

知道我在这里做错了吗?

1 个答案:

答案 0 :(得分:2)

您可以将doSomething的参数类型更改为Request,而不是MyRequest,它会起作用:

def doSomething(request: Request): MyResponse = {
    null
}

这是为什么?那么你不能将具有更具体的参数类型的函数赋值给具有较少特定参数类型的变量。如果doSomething的参数类型为MyRequestdoSomething正文中我们调用的方法仅在MyRequest上可用且在Request上不可用,如果有人用Request的不同实现调用myFunction,下面的例子会发生什么?我们会打破类型安全。

val myFunction: (Request) => Response = doSomething

我们可以在Function1特征的参数化类型中看到这一点:

trait Function1[-T1, +R]

-T1表示函数的参数是逆变的,这意味着具有较少特定参数类型的函数计为子类型(即Request => Response函数可以分配给类型为{{1}的变量})。 MyRequest => Response表示函数返回类型是协变的,这意味着具有更具体返回类型的+R计为子类型(即Function可以分配给Request => MyResponse类型的变量)。