Scala - 用边界覆盖类型成员
Scala - overriding type-member with bounds
我对 Scala 代码中的特征层次结构有以下问题:
首先,我有一个基本特征MyTrait[A]
,定义如下:
trait MyTrait[A] {
def v1: A
}
然后是具有类型成员的特征Base
的定义:
trait Base[A] {
type T <: MyTrait[A]
val baseV: T
}
最后,一个特征 Gen
覆盖了 Base
的类型成员。
trait Gen[A, X <: MyTrait[A]] extends Base[A] {
type T = X
}
问题是在 Gen
特性中,类型成员的边界似乎丢失了。这可以通过以下测试来证明:
编译:
trait Test1 {
val x: Base[_]
println(x.baseV.v1)
}
不编译 (value v1 is not a member of Test2.this.x.T
):
trait Test2 {
val x: Gen[_, _]
println(x.baseV.v1)
}
我想知道这是语言的限制还是有解决方法。关于 stackowerflow (1, ) 上类似主题的问题似乎侧重于与我不同的方面,我真的很茫然,因为我在 Scala 中找不到有关此类行为的太多信息。
本题的Scala代码模板可以在scastie
找到
这个有效:
trait Test2 {
val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
println(x.baseV.v1)
}
我认为问题在于
Gen[_, _]
Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]
与
相同
Gen[A, X] forSome { type A; type X }
也就是说,即使 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
我们可以明确地为通配符添加界限。然而,因为第二个通配符的绑定依赖于第一个通配符,我们被迫使用扩展的 forSome
语法来表示存在,所以我们可以命名 A
并使用它两次。
Gen[A, _ <: MyTrait[A]] forSome { type A }
我选择将所有内容都放在存在子句中,这等价于:
Gen[A, X] forSome { type A; type X <: MyTrait[A] }
您也可以使用
Gen[_, _ <: MyTrait[_]]
但这并不等价,因为它没有关联左右参数。如果 Gen[A, _]
除了 MyTrait[A]
之外还包含 A
,那么使用 x: Gen[_, _ <: MyTrait[_]]
将呈现 "bare" 值和 "wrapped" 值不兼容的类型.
我对 Scala 代码中的特征层次结构有以下问题:
首先,我有一个基本特征MyTrait[A]
,定义如下:
trait MyTrait[A] {
def v1: A
}
然后是具有类型成员的特征Base
的定义:
trait Base[A] {
type T <: MyTrait[A]
val baseV: T
}
最后,一个特征 Gen
覆盖了 Base
的类型成员。
trait Gen[A, X <: MyTrait[A]] extends Base[A] {
type T = X
}
问题是在 Gen
特性中,类型成员的边界似乎丢失了。这可以通过以下测试来证明:
编译:
trait Test1 {
val x: Base[_]
println(x.baseV.v1)
}
不编译 (value v1 is not a member of Test2.this.x.T
):
trait Test2 {
val x: Gen[_, _]
println(x.baseV.v1)
}
我想知道这是语言的限制还是有解决方法。关于 stackowerflow (1,
本题的Scala代码模板可以在scastie
找到这个有效:
trait Test2 {
val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
println(x.baseV.v1)
}
我认为问题在于
Gen[_, _]
Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]
与
相同Gen[A, X] forSome { type A; type X }
也就是说,即使 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
我们可以明确地为通配符添加界限。然而,因为第二个通配符的绑定依赖于第一个通配符,我们被迫使用扩展的 forSome
语法来表示存在,所以我们可以命名 A
并使用它两次。
Gen[A, _ <: MyTrait[A]] forSome { type A }
我选择将所有内容都放在存在子句中,这等价于:
Gen[A, X] forSome { type A; type X <: MyTrait[A] }
您也可以使用
Gen[_, _ <: MyTrait[_]]
但这并不等价,因为它没有关联左右参数。如果 Gen[A, _]
除了 MyTrait[A]
之外还包含 A
,那么使用 x: Gen[_, _ <: MyTrait[_]]
将呈现 "bare" 值和 "wrapped" 值不兼容的类型.