Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala抽象类型成员-继承和类型边界_Scala_Abstract Type_Type Bounds_Type Members - Fatal编程技术网

Scala抽象类型成员-继承和类型边界

Scala抽象类型成员-继承和类型边界,scala,abstract-type,type-bounds,type-members,Scala,Abstract Type,Type Bounds,Type Members,今天,当我试图细化抽象类型成员的类型边界时,在Scala中遇到了一些奇怪的情况 我有两个特性定义类型成员的边界,并将它们组合到一个具体的类中。这很好,但当匹配/铸造特征组合时,只有两个类型边界中的一个是“主动的”,我很难理解为什么 我试着准备一个例子: trait L trait R trait Left { type T <: L def get: T } trait Right { type T <: R } 我可以按计划通过get访问我的会员 // works

今天,当我试图细化抽象类型成员的类型边界时,在Scala中遇到了一些奇怪的情况

我有两个特性定义类型成员的边界,并将它们组合到一个具体的类中。这很好,但当匹配/铸造特征组合时,只有两个类型边界中的一个是“主动的”,我很难理解为什么

我试着准备一个例子:

trait L
trait R

trait Left {
  type T <: L
  def get: T
}

trait Right {
  type T <: R
}
我可以按计划通过get访问我的会员

// works fine
val x1: L with R = concrete.get
但是如果我强制转换为(左加右)或模式匹配,我将无法再访问该成员。根据顺序,我从左或右获得类型边界,但不是两者的组合

// can only access as R, L with R won't work
val x2: R = concrete.asInstanceOf[Left with Right].get

// can only access as L, L with R won' work
val x3: L = concrete.asInstanceOf[Right with Left].get
我知道Left with Right与Right with Left不是一回事,但在这两种情况下,两个类型边界都包含在内,所以为什么我只能使用一个呢


有人能解释一下为什么会发生这种情况吗?

第二种类型的成员会覆盖第一种类型的成员

trait L
trait R

trait Left {
  type T <: L
  def get: T
}

trait Right {
  type T <: R
}

object X {
  type LR = Left with Right // Right#T overrides Left#T, LR#T is now <: R
  type RL = Right with Left // Left#T overrides Right#T, LR#T is now <: L

  val concrete = new Left with Right {
    override type T = L with R
    override def get: T = new L with R {}
  }

  // ok
  val r: R = concrete.asInstanceOf[LR].get
  val l: L = concrete.asInstanceOf[RL].get

  // ok
  implicitly[LR#T <:< R]
  implicitly[RL#T <:< L]

  // doesn't compile, LR#T is a subclass of R because Right#T overrides Left#T
  implicitly[LR#T <:< L]
  // doesn't compile, RL#T is a subclass of L because Left#T overrides Right#T
  implicitly[RL#T <:< R]
}
trait L
性状R
左特征{

输入T除了TrustNoOne的答案之外,我可以建议以下有一些限制的解决方法。您可以设计自己的类型组合器,而不是使用
来克服类型重写

  trait L
  trait R
  trait Base {
    type T
    def get: T
  }
  trait Nil extends Base{
    type T = Any
  }
  trait ~+~[X[_ <: Base] <: Base, Y[_ <: Base] <: Base] extends Base {
    type T = Y[X[Nil]]#T
  }
  trait Left[B <: Base] extends Base {
    type T = B#T with L
  }
  trait Right[B <: Base] extends Base {
    type T = B#T with R
  }
  val concrete = new (Left ~+~ Right) {
    def get: T = new L with R {}
  }

  val x1: L with R = concrete.get
  val x2: R = concrete.asInstanceOf[Left ~+~ Right].get
  val x3: L = concrete.asInstanceOf[Right ~+~ Left].get
trait L
性状R
性状基础{
T型
def get:T
}
性状零延伸基{
类型T=任何
}

性状~+~[X[;你可以阅读更多关于为什么现在scala覆盖类型以及如何在下一代scala的概念中实现不同的内容我还没来得及深入探讨dotty,但我肯定很期待!你可以在这段视频中看到一些关于未来惊人的东西。关于Shapeled的评论包括Hey,tanks的详细回答Hey,t如果我理解正确的话:问题是
左带右
是一个将T绑定到的类型,它不能被实例化(
trait-error扩展为左带右
没有编译,因为R!=L)正确的类型是
asInstanceOf[Left with Right]{type T=L with R}
也有效(-:
  trait L
  trait R
  trait Base {
    type T
    def get: T
  }
  trait Nil extends Base{
    type T = Any
  }
  trait ~+~[X[_ <: Base] <: Base, Y[_ <: Base] <: Base] extends Base {
    type T = Y[X[Nil]]#T
  }
  trait Left[B <: Base] extends Base {
    type T = B#T with L
  }
  trait Right[B <: Base] extends Base {
    type T = B#T with R
  }
  val concrete = new (Left ~+~ Right) {
    def get: T = new L with R {}
  }

  val x1: L with R = concrete.get
  val x2: R = concrete.asInstanceOf[Left ~+~ Right].get
  val x3: L = concrete.asInstanceOf[Right ~+~ Left].get