you*_*tur 5 generics scala traits type-bounds type-members
我在Scala代码中的traits层次结构存在以下问题:
首先,我有一个MyTrait[A]具有这样定义的基本特征:
trait MyTrait[A] {
def v1: A
}
Run Code Online (Sandbox Code Playgroud)
然后是一个Base带有类型成员的特征定义:
trait Base[A] {
type T <: MyTrait[A]
val baseV: T
}
Run Code Online (Sandbox Code Playgroud)
并且,最后,一个特征Gen覆盖了Base类型成员.
trait Gen[A, X <: MyTrait[A]] extends Base[A] {
type T = X
}
Run Code Online (Sandbox Code Playgroud)
问题是在Gen特征中似乎丢失了类型成员的边界.这可以通过以下测试证明:
编译:
trait Test1 {
val x: Base[_]
println(x.baseV.v1)
}
Run Code Online (Sandbox Code Playgroud)
不编译(value v1 is not a member of Test2.this.x.T):
trait Test2 {
val x: Gen[_, _]
println(x.baseV.v1)
}
Run Code Online (Sandbox Code Playgroud)
我想知道这是语言的限制还是有解决方法.针对以上类似问题上stackowerflow问题(1,2)似乎把重点放在比我的不同方面,我真的不知所措,因为我无法找到有关Scala的这种行为多的信息.
可以在scastie上找到此问题的Scala代码模板
这有效:
trait Test2 {
val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
println(x.baseV.v1)
}
Run Code Online (Sandbox Code Playgroud)
我相信问题是这样的
Gen[_, _]
Run Code Online (Sandbox Code Playgroud)
Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]
Run Code Online (Sandbox Code Playgroud)
哪个是一样的
Gen[A, X] forSome { type A; type X }
Run Code Online (Sandbox Code Playgroud)
也就是说,即使边界Gen说X <: MyTrait[A],通配符也没有继承那个边界.你可以在这里看到类似的问题:
trait Data { def data: String }
trait Box[A <: Data] { def data: A }
def unbox(b: Box[_]): String = b.data.data // nope; the wildcard is not <: Data
Run Code Online (Sandbox Code Playgroud)
我们可以明确地将通配符添加到通配符.但是,因为第二个通配符上的绑定取决于第一个通配符forSome,所以我们不得不使用扩展语法来存在,所以我们可以命名A并使用它两次.
Gen[A, _ <: MyTrait[A]] forSome { type A }
Run Code Online (Sandbox Code Playgroud)
我选择将所有内容都放在存在主义条款中,这相当于:
Gen[A, X] forSome { type A; type X <: MyTrait[A] }
Run Code Online (Sandbox Code Playgroud)
你也可以使用
Gen[_, _ <: MyTrait[_]]
Run Code Online (Sandbox Code Playgroud)
但这不等同,因为它与左右参数无关.如果除了a之外还Gen[A, _]包含A一个MyTrait[A],那么using x: Gen[_, _ <: MyTrait[_]]会使用不兼容的类型呈现"裸"值和"包装"值.