存在类型和类型成员

Tra*_*own 12 generics types scala existential-type type-members

什么有效(A部分​​)

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

trait A[T]
Run Code Online (Sandbox Code Playgroud)

我可以使用存在类型来编写一个方法,该方法将采用A所有具有相同的s 的集合T:

def foo(as: Seq[A[X]] forSome { type X }) = true
Run Code Online (Sandbox Code Playgroud)

请注意,这与以下内容不同:

def otherFoo(as: Seq[A[X] forSome { type X }]) = true
Run Code Online (Sandbox Code Playgroud)

或等效的:

def otherFoo(as: Seq[A[_]]) = true
Run Code Online (Sandbox Code Playgroud)

在这些情况下,存在主义的范围在里面Seq,所以As可以有不同的Ts.使用我的原始foo(存在范围Seq),以下是好的:

foo(Seq(new A[Int] {}, new A[Int] {}))
Run Code Online (Sandbox Code Playgroud)

但是使类型参数不同并且不能编译:

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] {}))
                     ^
Run Code Online (Sandbox Code Playgroud)

这一切都非常简单.

什么有效(B部分)

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

trait B { type T }
Run Code Online (Sandbox Code Playgroud)

我可以编写一个方法,只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 })
                          ^
Run Code Online (Sandbox Code Playgroud)

同样,这完全符合您的预期.

什么行不通

当我们尝试编写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
Run Code Online (Sandbox Code Playgroud)

最后一行编译对我来说毫无意义.我告诉它我希望所有类型的成员都是一样的.我foo表明我可以为类型参数执行此操作,并bar显示我可以基于其类型成员约束类型.但我无法将两者结合起来.

我在2.9.2和2.10.0-M5上试过这个.

动机

这个问题的灵感来自于这个问题,我的第一个想法是,哦,只使用存在类型(暂时搁置一个问题,似乎不可能将存在类型变为重复参数类型的范围,这将是方便的):

def accept(rs: Seq[RList[Int] { type S = X }] forSome { type X }) = true
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*las 3

我终于解决了(至少我希望如此)。我们换个方式来做吧。我们建立我们的特质:

scala> trait B {type T}
defined trait B
Run Code Online (Sandbox Code Playgroud)

我们尝试构建一个序列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)
Run Code Online (Sandbox Code Playgroud)

该死的,它有效!好吧,我们没有等式,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)
Run Code Online (Sandbox Code Playgroud)

更近了。不等等,它不是更接近,它比你建议的参数更好baz,我们不仅提供原始类型,我们还有一个上限!这样,我们就可以清楚地将它传递给baz. 这就是为什么它不能按您的预期工作的原因。