[英]Existential types and type members
假设我有一个带有类型参数的特征:
trait A[T]
我可以使用存在类型来编写一个方法,该方法将采用所有具有相同T
的A
的集合:
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
s可以具有不同的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 }
我可以编写一个只带有一些指定T
的B
的方法:
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上试过这个。
这个问题的灵感来自于这个问题,我的第一个想法是,哦,只使用存在类型(暂时搁置一个问题, 似乎不可能将存在类型转换为重复参数类型的范围 ,这将是方便的):
def accept(rs: Seq[RList[Int] { type S = X }] forSome { type X }) = true
但这实际上并不起作用 - 你得到了与上面简化例子中相同的奇怪结果。
我终于解决了(至少我希望如此)。 让我们以另一种方式做。 我们建立我们的特质:
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
。 这就是它无法按预期工作的原因。
在你的例子中:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.