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
}