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

时间:2015-01-29 23:52:04

标签: scala generics lambda

假设我有Thing的接口:

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

我按如下方式实施Thing

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

此外,假设我有一个函数,它将Thing和一个lambda作为参数执行Thing

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。极好!编译器可以告诉SpecificThingThing[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[?]

1 个答案:

答案 0 :(得分:6)

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]中是逆变

A Thing[?]就是它的样子;对于某种未知类型Thing[X],它是X。编译器正试图推断类型A应该是什么,但是它不能使它工作:对于某些(未知到它)类型{{1}它需要Thing[A] => A你将A传递给你;这是错误。