假设我有一个带有类型参数的特征:
trait A[T]
我可以使用存在类型来编写一个方法,该方法将收集A
个具有相同T
的集合:
def foo(as: Seq[A[X]] forSome { type X }) = true
请注意,这与以下内容不同:
def otherFoo(as: Seq[A[X] forSome { type X }]) = true
或同等的:
def otherFoo(as: Seq[A[_]]) = true
在这些情况下,存在主义的范围在Seq
内,因此A
可以有不同的T
s。使用我的原始foo
(对Seq
的存在范围确定),以下情况很好:
foo(Seq(new A[Int] {}, new A[Int] {}))
但是使类型参数不同并且不能编译:
scala> foo(Seq(new A[Int] {}, new A[String] {}))
<console>:10: error: type mismatch;
found : Seq[A[_ >: java.lang.String with Int]]
required: Seq[A[X]] forSome { type X }
foo(Seq(new A[Int] {}, new A[String] {}))
^
这一切都非常简单。
现在假设我有类型成员的类似特征而不是类型参数:
trait B { type T }
我可以编写一个只会B
指定T
的方法:
scala> def bar[X](b: B { type T = X }) = true
bar: [X](b: B{type T = X})Boolean
scala> bar[Int](new B { type T = Int })
res5: Boolean = true
scala> bar[String](new B { type T = Int })
<console>:10: error: type mismatch;
found : java.lang.Object with B
required: B{type T = String}
bar[String](new B { type T = Int })
^
同样,这完全符合您的预期。
当我们尝试编写上面的foo
的等价物,但对于类型成员,事情变得奇怪。
scala> def baz(bs: Seq[B { type T = X }] forSome { type X }) = true
baz: (as: Seq[B{type T = X}] forSome { type X })Boolean
scala> baz(Seq(new B { type T = Int }, new B { type T = String }))
res7: Boolean = true
最后一行编译对我来说毫无意义。我告诉它我希望所有类型的成员都是一样的。我的foo
表明我可以为类型参数执行此操作,而bar
表示我可以根据其类型成员约束类型。但我无法将两者结合起来。
我在2.9.2和2.10.0-M5上试过这个。
这个问题的灵感来自于this one,我的第一个想法是,哦,只是使用一种存在主义类型(暂时搁置it seems to be impossible to get an existential type to scope of the type of a repeated parameter的问题,这在这里很方便):< / p>
def accept(rs: Seq[RList[Int] { type S = X }] forSome { type X }) = true
但这实际上并不起作用 - 你得到了与上面简化例子中相同的奇怪结果。
答案 0 :(得分:3)
我终于解决了(至少我希望如此)。让我们以另一种方式做。我们建立了自己的特质:
scala> trait B {type T}
defined trait B
我们尝试构建一系列B
:
scala> Seq(new B {type T = Int}, new B {type T = String})
res0: Seq[B{type T >: String with Int}] = List($anon$1@592b12d, $anon$2@61ae0436)
该死的,它有效!好吧,type T
我们没有平等,但让我们玩它:
scala> res0 : (Seq[B {type T = X}] forSome {type X >: String with Int})
res1: Seq[B{type T = X}] forSome { type X >: String with Int } = List($anon$1@592b12d, $anon$2@61ae0436)
它更接近了。没有等待,它没有更接近,它比你提出的baz
的参数更好,我们不仅提供原始类型,我们还有一个上限!因此,我们可以清楚地将其传递给baz
。这就是为什么它不能按预期工作的原因。
答案 1 :(得分:-1)
在你的例子中:
scala> def baz(bs: Seq[B { type T = X }] forSome { type X }) = true
告诉编译器函数baz采用特征B的Seq。特征B碰巧采用类型成员T,但就编译器而言,即使B类型成员T的类型不相同,函数baz也可以采用特征B的Seq。如果你希望函数baz采用具有相同类型成员的特征B的Seq,你需要告诉编译器如下:
scala> def baz[X](bs: Seq[B { type T = X }]) = true
baz: [X](bs: Seq[B{type T = X}])Boolean
scala> baz[Int](Seq(new B { type T = Int }, new B { type T = String }))
<console>:10: error: type mismatch;
found : java.lang.Object with B
required: B{type T = Int}
baz[Int](Seq(new B { type T = Int }, new B { type T = String }))
^
scala> baz[Int](Seq(new B { type T = Int }, new B { type T = Int }))
res10: Boolean = true