Generics Scala中具有存在类型的泛型

Generics Scala中具有存在类型的泛型,generics,scala,Generics,Scala,一个关于两个特性的故事,看起来应该很好地结合在一起,但是我不能理解为什么这段代码不起作用,或者编译错误到底想告诉我什么 所以。。。我们有 父母的一个特点 trait PolyTreeHasParents[P <: PolyTreeHasChildren[_]] { val _parents: ListBuffer[P] = ListBuffer() def isRootNode = _parents.size == 0 def parents: List[P] = _paren

一个关于两个特性的故事,看起来应该很好地结合在一起,但是我不能理解为什么这段代码不起作用,或者编译错误到底想告诉我什么

所以。。。我们有

父母的一个特点

trait PolyTreeHasParents[P <: PolyTreeHasChildren[_]]  { 


val _parents: ListBuffer[P] = ListBuffer()

def isRootNode = _parents.size == 0

def parents: List[P] = _parents.readOnly

def addParent(parent: P): PolyTreeHasParents[P] = {

    println(parent)

    if (parent == this)
        throw new IllegalArgumentException()

    _parents += parent

    // 

    this
}




} 
我会认为

P :< PolyTreeHasParents[_]
什么


唉。。。我已经没有办法让这段代码工作了:(

你可以通过两种方法避免这种明显的无限循环:

首先,删除不必要的类型边界()——至少在当前的
polytreehasportents
实现中,没有必要说
p
必须是
polytreehasphildren
的子类型

其次,您可以向
PolyTreeHasChildren
添加另一个类型参数,指定实现类型,并将其用作自类型。我认为这是集合库中的常见模式

它看起来是这样的:

import collection.mutable.ListBuffer

trait PolyTreeHasParents[P] { 
   val _parents: ListBuffer[P] = ListBuffer()
   def isRootNode = _parents.size == 0
   def parents: List[P] = _parents.readOnly
   def addParent(parent: P): PolyTreeHasParents[P] = {
      require (parent != this)
      _parents += parent
      this
   }
}

trait PolyTreeHasChildren[Repr, C <: PolyTreeHasParents[Repr]] {   
   me: Repr =>

   val _children: ListBuffer[C] = ListBuffer()
   def isLeafNode = children == ListBuffer()
   def children: List[C] = _children.readOnly
   def += (child: C) : Repr = {
      addChild(child)
   }

   def addChild(child: C): Repr = {
      require (child != this)
      _children += child
      child.addParent(this)
      this
   }
}
import collection.mutable.ListBuffer
性状多树型糖蛋白[P]{
val_父项:ListBuffer[P]=ListBuffer()
def isRootNode=\u parents.size==0
def parents:List[P]=\u parents.readOnly
def addParent(父级:P):PolyTreeHasParents[P]={
需要(父项!=此项)
_家长+=家长
这
}
}
性状多树型血子弟[Repr,C
val_子项:ListBuffer[C]=ListBuffer()
def isLeafNode=children==ListBuffer()
def children:List[C]=\u children.readOnly
def+=(子项:C):报告={
addChild(child)
}
def addChild(子项:C):报告={
需要(孩子!=这个)
_儿童+=儿童
child.addParent(此)
这
}
}

您尝试过类似的方法吗

 trait PolyTreeHasParents[P <: PolyTreeHasChildren[PolyTreeHasParents[P]]]  { }

 trait PolyTreeHasChildren[C <: PolyTreeHasParents[PolyTreeHasChildren[C]]]  { }

trait polytreehasportents[P

错误消息看起来很奇怪,但在这种疯狂中有方法。 它的意思是:您正在传入一个已知类型的参数,但您已将其指定为某个未知类型的参数,在本例中,该参数被skolomized为$1

在代码中,您可以完全删除类型参数:

trait PolyTreeHasParents {
  type P = PolyTreeHasChildren
  val _parents: ListBuffer[P] = ListBuffer()
  def isRootNode = _parents.size == 0
  def parents: List[P] = _parents.readOnly

  def addParent(parent: P): PolyTreeHasParents = {

    if (!_parents.contains(parent)) {
      println(parent)
      if (parent == this) throw new IllegalArgumentException()
      _parents += parent
      parent.addChild(this)
    }
    this
  }
}

trait PolyTreeHasChildren {
  type C = PolyTreeHasParents
  val _children: ListBuffer[C] = ListBuffer()

  def isLeafNode = children == ListBuffer()

  def children: List[C] = _children.readOnly

  def +=(child: C): PolyTreeHasChildren = {
    addChild(child)
  }

  def addChild(child: C): PolyTreeHasChildren = {
    if (!_children.contains(child)) {
      println(child)
      if (child == this)
        throw new IllegalArgumentException()
      _children += child
      child.addParent(this)
    }
    this
  }
}
请参见此行为:

object Test {
  def main(args: Array[String]) {
    trait X extends PolyTreeHasParents with PolyTreeHasChildren
    trait Y extends PolyTreeHasParents with PolyTreeHasChildren
    val x0, x1, x2 = new  X {}
    val y0, y1, y2 = new  Y {}
    x0.addChild(x1)
    x1.addChild(x2)
    y2.addParent(y1)
    y1.addParent(y0)
    x0.addParent(y2)
  }
}
现在让我们将其与“n.m.”解的行为进行比较:


类型参数边界的复杂性源于这样一个事实:您的PolyTree由两个特征组成。一个包含父特征,另一个包含子特征

我不明白拥有这些独立特征的用例可能是什么。因为在一个多元树中,一般来说,所有节点都可能有子节点和/或父节点。所以我认为人们总是会将它们混合在一起

如果是这种情况,则可以消除类型参数边界的复杂性:

trait PolyTree[Self <: PolyTree[Self] ] {
  self: Self =>

  private val _parents: ListBuffer[Self] = ListBuffer()
  def isRootNode = _parents.isEmpty
  def parents: List[Self] = _parents.readOnly

  def addParent(parent: Self): Self = {

    if (!_parents.contains(parent)) {
      println(parent)
      if (parent == this) throw new IllegalArgumentException()
      _parents += parent
      parent.addChild(this)
    }
    this
  }

  private val _children: ListBuffer[Self] = ListBuffer()
  def isLeafNode = _children.isEmpty
  def children: List[Self] = _children.readOnly

  def addChild(child: Self): Self = {
    if (!_children.contains(child)) {
      println(child)
      if (child == this)
        throw new IllegalArgumentException()
      _children += child
      child.addParent(this)
    }
    this
  }

}

除此之外:polytree是非循环的。您仍然需要添加代码来防止循环的创建。

Nice!工作得很好!感谢您强调该特征不能添加它已经添加的子项。进行了一些小更改…而不是if(Parent==this)…,将其更改为require(child!=this)。此外…从可变列表移动到不可变列表。如果PolytreehAspElements都有一个addParent方法,PolyTreeHasChildren有一个addChild方法(如n.m.提供的答案中所示),这是否同样有效?当然,请参阅上面的代码。使此代码更简单的是,它允许您将PolyTreeHasChildren的任何内容添加到PolyTreeHa的任何内容中在n.m.的解决方案中,您可以将其限制为特定类型,并对其进行类型检查。但我无法从您的问题中弥补您确实需要它。
trait PolyTreeHasParents[Repr <: PolyTreeHasParents[Repr, P], 
      P <: PolyTreeHasChildren[P, Repr]]  {   

me: Repr =>

    val _parents: ListBuffer[P] = ListBuffer()
    def isRootNode = _parents.size == 0
    def parents: List[P] = _parents.readOnly
    def addParent(parent: P): Repr = { 
        if (! _parents.contains(parent) {
            println(parent)
            if (parent == this)
            throw new IllegalArgumentException()
            _parents += parent
            parent.addChild(this)
        }
        this
    }
}

trait PolyTreeHasChildren[Repr <: PolyTreeHasChildren[Repr, C],
      C <: PolyTreeHasParents[C, Repr]]  {

me: Repr =>

    val _children: ListBuffer[C] = ListBuffer()
    def isLeafNode = children == ListBuffer()
    def children: List[C] = _children.readOnly
    def += (child: C) : PolyTreeHasChildren[Repr, C] = { 
        addChild(child)
    }
    def addChild(child: C): Repr = { 
        if (! _children.contains(child) {
            println(child)
            if (child == this)
              throw new IllegalArgumentException()
            _children += child
            child.addParent(this)
        }
        this
    }
}

// Usage example
class PP extends PolyTreeHasChildren[PP, CC]
class CC extends PolyTreeHasParents[CC, PP]
trait PolyTreeHasParents {
  type P = PolyTreeHasChildren
  val _parents: ListBuffer[P] = ListBuffer()
  def isRootNode = _parents.size == 0
  def parents: List[P] = _parents.readOnly

  def addParent(parent: P): PolyTreeHasParents = {

    if (!_parents.contains(parent)) {
      println(parent)
      if (parent == this) throw new IllegalArgumentException()
      _parents += parent
      parent.addChild(this)
    }
    this
  }
}

trait PolyTreeHasChildren {
  type C = PolyTreeHasParents
  val _children: ListBuffer[C] = ListBuffer()

  def isLeafNode = children == ListBuffer()

  def children: List[C] = _children.readOnly

  def +=(child: C): PolyTreeHasChildren = {
    addChild(child)
  }

  def addChild(child: C): PolyTreeHasChildren = {
    if (!_children.contains(child)) {
      println(child)
      if (child == this)
        throw new IllegalArgumentException()
      _children += child
      child.addParent(this)
    }
    this
  }
}
object Test {
  def main(args: Array[String]) {
    trait X extends PolyTreeHasParents with PolyTreeHasChildren
    trait Y extends PolyTreeHasParents with PolyTreeHasChildren
    val x0, x1, x2 = new  X {}
    val y0, y1, y2 = new  Y {}
    x0.addChild(x1)
    x1.addChild(x2)
    y2.addParent(y1)
    y1.addParent(y0)
    x0.addParent(y2)
  }
}
object Test {
  def main(args: Array[String]) {
    trait X extends PolyTreeHasParents[X, X] with PolyTreeHasChildren[X, X]
    trait Y extends PolyTreeHasParents[Y, Y] with PolyTreeHasChildren[Y, Y]
    val x0, x1, x2 = new X {}
    val y0, y1, y2 = new Y {}
    x0.addChild(x1)
    x1.addChild(x2)
    y2.addParent(y1)
    y1.addParent(y0)
//    x0.addParent(y2) // will not compile
  }
}      
trait PolyTree[Self <: PolyTree[Self] ] {
  self: Self =>

  private val _parents: ListBuffer[Self] = ListBuffer()
  def isRootNode = _parents.isEmpty
  def parents: List[Self] = _parents.readOnly

  def addParent(parent: Self): Self = {

    if (!_parents.contains(parent)) {
      println(parent)
      if (parent == this) throw new IllegalArgumentException()
      _parents += parent
      parent.addChild(this)
    }
    this
  }

  private val _children: ListBuffer[Self] = ListBuffer()
  def isLeafNode = _children.isEmpty
  def children: List[Self] = _children.readOnly

  def addChild(child: Self): Self = {
    if (!_children.contains(child)) {
      println(child)
      if (child == this)
        throw new IllegalArgumentException()
      _children += child
      child.addParent(this)
    }
    this
  }

}
object UseCasePolyTree {
  trait X extends PolyTree[X]
  trait Y extends PolyTree[Y]
  val x0, x1, x2 = new X {}
  val y0, y1, y2 = new Y {}
  x0.addChild(x1)
  x1.addChild(x2)
  val xx1: X = x2.parents.head
  y2.addParent(y1)
  y1.addParent(y0)
//  x0.addParent(y2) // will not compile
}