是否有人能够阐明这两个例子之间的真正差异。
object ExampleA {
trait Bar { def n: Int }
trait Foo[B <: Bar] { def bar: B }
def getBarIntFromFoo(foo: Foo[_]) =
getBarInt(foo.bar)
def getBarInt(bar: Bar) =
bar.n
}
object ExampleB {
trait Bar { def n: Int }
trait Foo {
type B <: Bar
def bar: B
}
def getBarIntFromFoo(foo: Foo) =
getBarInt(foo.bar)
def getBarInt(bar: Bar) =
bar.n
}
我认为唯一的区别在于你引用它们的方式,但实际上只有ExampleB
编译而ExampleA
会导致:
[error] type mismatch;
[error] found : _$1
[error] required: ExampleA.Bar
[error] getBarInt(_)
[error] ^
两个Foo
都有相同的类型约束(B <: Bar
),所以我有点迷失。我想我只是误解了一些非常基本的东西。
答案 0 :(得分:3)
_
中的Foo[_]
是一种存在类型。如果Any
的上限为Foo[B]
,则不会在其上设置任何类型边界,它将被假定为Bar
。这意味着foo.bar
被假定为Any
,而不是Bar
。因此,getBarInt(foo.bar)
失败,因为编译器认为您正在传递Any
而不是Bar
。
如果您希望参数为Foo[_]
,则必须在此处限定。
object ExampleA {
trait Bar { def n: Int }
trait Foo[B <: Bar] { def bar: B }
def getBarIntFromFoo(foo: Foo[_ <: Bar]) =
getBarInt(foo.bar)
def getBarInt(bar: Bar) =
bar.n
}
来自SLS:
Scala支持存在类型的占位符语法。通配符类型的格式为
_ >: L <: U
。两个绑定条款都可以省略。如果缺少下限项>: L
,则假定为>: scala.Nothing
。 如果缺少上限条款<: U
,则假定<: scala.Any
。通配符类型是存在量化类型变量的简写,其中存在量化是隐含的。
带有别名类型的第二个示例并不会受此影响。
答案 1 :(得分:3)
m-z在这里是正确的。但您可能会问的一个问题是,为什么Scala要求您在<: Bar
的定义已经要求时重复绑定Foo
?
原因是为了与
保持一致def blah[A](f: Foo[A])
这里[A]
将由调用者提供,因此不允许Foo对其应用任何额外的约束(否则很难确定blah的确切定义)。这意味着,通常Foo[x]
无法对X
应用约束,即使在某些情况下它也是安全的。
但是,未来有计划将存在类型重新实现为类型变量,所以这种行为可能会在某一天发生变化。