你不能使用Foo[Bleh]
asFoo[Blah]
因为Foo[Bleh]
is not a Foo[Blah]
。您应该对使用as进行Foo
逆变。A
Foo[Bleh]
Foo[Blah]
trait Foo[-A] {
def bar(a: A) = println(a) // to make Foo contravariant
}
这工作得很好:
scala> foo1(Blah())
res0: Blah = Blah()
您的原始代码包含您问题的答案。假设您可以将原件Foo[Bleh]
用作Foo[Blah]
:
def foo1[A:Foo](): A = implicitly[Foo[A]].bar
val b: Blah = foo1[Blah]()
如果在此处使用 case Foo[Bleh]
,您将得到Bleh
的结果bar
,但您期望Blah
并且Bleh
不是Blah
.
幸运的是,编译器不允许您将原始文件Foo[Bleh]
用作Foo[Blah]
:
scala> trait Foo[-A] {
| def bar: A
| }
<console>:8: error: contravariant type A occurs in covariant position in type => A of method bar
def bar: A
^
类型推断
这工作正常:
foo1[Bleh](Blah())
但是编译器不会A
在这里将类型参数推断为Bleh
. 为了理解“为什么”,我们应该知道什么A:Foo
意思:
def foo1[A:Foo](a:A) = a // syntax sugar
def foo1[A](a:A)(implicit ev: Foo[A]) = a // same method
A:Foo
是添加隐式参数的语法糖。
如果您有 2 个参数组,编译器将推断第一组中的类型,然后认为该类型已知。因此,在第一个参数组(a:A)
类型Blah
的类型推断已知并且第二个参数组不能影响类型参数之后。