我经常在Scala中遇到以下问题:
给出一个特质
trait Foo { def foo: String }
和参数化类
case class Bar[T <: Foo](t: T)
我想编写一个与Bar
一起使用的方法而不重复类型约束,例如:
def doSth(bar: Bar[_]) = bar.t.foo
不幸的是,它没有编译,我需要写:
def doSth[T <: Foo](bar: Bar[T]) = bar.t.foo
为什么编译器无法推断如果我有Bar[_]
,_
必须是Foo
?
是否有解决方法(抽象类型会避免重复,但会增加表示某些约束的复杂性)?
答案 0 :(得分:2)
似乎
def doSth(bar: Bar[_]) = bar.t.foo
与
基本相同def doSth0(bar: Bar[X] forSome { type X }) = bar.t.foo
和type X
完全不受约束。因此,我认为这个问题应该是:
为什么编译器完全允许Bar[X] forSome { type X }
之类的东西,即使X
未被声明为Foo
的子类型,而Bar
需要参数是Foo
的子类型?
我不知道答案。可能它再次与java泛型有关。
<强>变通方法强>
鉴于特质和阶级
trait Foo { def foo: String }
case class Bar[T <: Foo](t: T)
以下两个定义在没有其他类型参数的情况下工作:
def doSth1(bar: Bar[X] forSome { type X <: Foo }) = bar.t.foo
def doSth2(bar: Bar[_ <: Foo]) = bar.t.foo
另一种选择是约束t
本身Bar
的类型:
case class Bar2[T <: Foo](t: T with Foo)
def doSth3(bar: Bar2[_]) = bar.t.foo