为什么 Scala 编译器不接受这个 lambda 作为参数?

Why doesn't the Scala compiler accept this lambda as a parameter?

假设我有一个 Thing:

的接口
abstract class Thing[A](a_thing: A) {
  def thingA = a_thing
}

我按如下方式实现 Thing

class SpecificThing(a: String) extends Thing[String](a)

此外,假设我有一个函数,它接受一个 Thing 和一个对 Thing 做某事的 lambda 作为参数:

def doSomething[A](fn: Thing[A] => A, t: Thing[A]) : A = fn(t)

现在,让我们使用这些东西:

val st = new SpecificThing("hi")
val fn1: (Thing[String]) => String = (t: Thing[String]) => { t.thingA }
println(doSomething(fn1, st))

这会打印 hi。到目前为止,一切都很好。但是我比较懒,不喜欢打那么多,所以我把程序改成下面这样:

type MyThing = Thing[String]
val st = new SpecificThing("hi")
val fn2: (MyThing) => String = (t: MyThing) => { t.thingA }
println(doSomething(fn2, st))

这也打印 hi。极好!编译器可以分辨出 SpecificThing 既是 Thing[String] 又是 MyThing。但是这个案例呢?

val st = new SpecificThing("hi")
val fn3: (SpecificThing) => String = (t: SpecificThing) => { t.thingA }
println(doSomething(fn3, st))

现在我得到:

Error:(14, 23) type mismatch;
 found   : SpecificThing => String
 required: Thing[?] => ?
  println(doSomething(fn3, st))
                      ^

这是怎么回事?什么是 Thing[?]

f3 不是 Thing[String] => String,而是 SpecificThing => String。例如,为什么它们不兼容:

class SpecificThing2 extends Thing[String] {
  def thingB = 2.0
}
val f4: SpecificThing2 => String = {
  st: SpecificThing2 => f"%f${st.thingB / 3.0}"
}
val t = new Thing[String]("haha"){}
f4(t) // would be an error when f4 tried to access t.thingB

更正式地说,Function1 在其第一个类型参数 Function1[-T, +R].

中是 逆变

一个Thing[?]就是这个样子;它是某种未知类型 XThing[X]。编译器正在大胆地尝试推断类型 A 应该是什么,但它无法使其工作:它需要一个 Thing[A] => A 用于某些(未知的)类型 A ,并且您将其传递给 SpecificThing => String;那是错误。