存在类型和类型成员

时间:2012-08-21 01:31:48

标签: scala generics types existential-type type-members

什么有效(A部分​​)

假设我有一个带有类型参数的特征:

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] {}))
                     ^

这一切都非常简单。

什么有效(B部分)

现在假设我有类型成员的类似特征而不是类型参数:

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

但这实际上并不起作用 - 你得到了与上面简化例子中相同的奇怪结果。

2 个答案:

答案 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