2015-01-29 7 views
1

Предположим, у меня есть интерфейс для Thing:Почему компилятор Scala не принимает эту лямбду в качестве параметра?

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

и я реализую, что Thing следующим образом:

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

Кроме того, предположим, что у меня есть функция, которая принимает Thing и лямбда, что делает что-то к тому, что Thing в качестве параметров:

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

Нет w, давайте использовать этот материал:

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[?]?

ответ

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, но он не может заставить его работать: ему нужен Thing[A] => A для некоторого (неизвестного для него) типа A, и вы передаете его SpecificThing => String; это ошибка.

Смежные вопросы