简体   繁体   English

Scala-用边界覆盖类型成员

[英]Scala - overriding type-member with bounds

I have the following problem with hierarchy of traits in Scala code: Scala代码中的特征层次结构存在以下问题:

First of all, I have a basic trait MyTrait[A] with such definition: 首先,我有一个基本特征MyTrait[A] ,其定义如下:

trait MyTrait[A] {
  def v1: A
}

It is then followed by a definition of a trait Base with a type-member: 然后是带有类型成员的特征Base的定义:

trait Base[A] {
  type T <: MyTrait[A]
  val baseV: T
}

And, at last, a trait Gen which overrides Base 's type member. 并且,最后,一个特征Gen覆盖了Base的类型成员。

trait Gen[A, X <: MyTrait[A]] extends Base[A] {
  type T = X
}

The problem is that in the Gen trait it seems that bounds of the type-member are lost. 问题在于,在Gen特质中,似乎失去了类型成员的界限。 This can be proven by following tests: 可以通过以下测试证明这一点:

Compiles: 编译:

trait Test1 {
  val x: Base[_]
  println(x.baseV.v1)
}

Doesn't compile ( value v1 is not a member of Test2.this.xT ): 不编译( value v1 is not a member of Test2.this.xT ):

trait Test2 {
  val x: Gen[_, _]
  println(x.baseV.v1)
}

I would like to know whether it's a limitation of the language or there is a workaround it. 我想知道这是语言的限制还是有解决方法。 Questions on similar topics on stackowerflow ( 1 , 2 ) appear to be focusing on different aspects than mine and I am genuinely at a loss because I can't find much information about such behavior in Scala. 上stackowerflow(相似主题的问题12 )似乎把重点放在比我的不同方面,我真的不知所措,因为我无法找到有关Scala的这种行为多的信息。

Scala code template of this question can be found on scastie 可以在scastie上找到此问题的Scala代码模板

This works: 这有效:

trait Test2 {
  val x: Gen[A, X] forSome { type A; type X <: MyTrait[A] }
  println(x.baseV.v1)
}

I believe the issue is that 我相信问题是

Gen[_, _]

Has to mean 必须是指

Gen[_ >: Nothing <: Any, _ >: Nothing <: Any]

Which is the same as 与...相同

Gen[A, X] forSome { type A; type X }

That is, even though the bounds on Gen say that X <: MyTrait[A] , the wildcards do not inherit that bound. 也就是说,即使Gen的边界说X <: MyTrait[A] ,通配符也不会继承该边界。 You can see a similar problem here: 您可以在这里看到类似的问题:

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

We can add the bounds to the wildcards explicitly. 我们可以将边界显式添加到通配符。 However, because the bound on the second wildcard depends on the first one, we are forced to use the extended forSome syntax for the existential, so we can name A and use it twice. 但是,由于第二个通配符的界限取决于第一个通配符,因此我们被迫将扩展的forSome语法用于存在性,因此我们可以命名A并使用两次。

Gen[A, _ <: MyTrait[A]] forSome { type A }

And I opted to just put everything in the existential clause, which is equivalent: 而且我选择将所有内容都放入存在子句中,这等效:

Gen[A, X] forSome { type A; type X <: MyTrait[A] }

You can also use 您也可以使用

Gen[_, _ <: MyTrait[_]]

but this is not equivalent, as it doesn't relate the left and right parameters. 但这并不等效,因为它与left和right参数无关。 If Gen[A, _] contained an A in addition to a MyTrait[A] , then using x: Gen[_, _ <: MyTrait[_]] would render the "bare" value and the "wrapped" value with incompatible types. 如果Gen[A, _]MyTrait[A]之外还包含A ,则使用x: Gen[_, _ <: MyTrait[_]]将使“裸”值和“包装”值不兼容。类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM