scala - 为什么我不能在扩展通用特征的类中调用参数为 `this` 的方法?

标签 scala generics traits

我正在编写一个特征来描述层次结构(如图表)中的类似节点的对象。我的工作代码如下:

trait Hierarchical[T <: Hierarchical[_]] {
  // The parents will be a list of some arbitrary Hierarchical
  val parents: List[Hierarchical[_]] = Nil
  var children: List[Hierarchical[T]] = List()

  def addChild(child: Hierarchical[T]): Unit = {
    children ++= List(child)
  }
}

abstract class NonRootNode(override val parents: List[Hierarchical[_]])
  extends Hierarchical[NonRootNode] {
}

abstract class RootNode extends Hierarchical[NonRootNode] {
  final override val parents = Nil
}

我有一些测试反射(reflect)了这种行为:

import org.scalatest.FlatSpec

class DummyRoot extends RootNode
class DummyNonRoot(override val parents: List[DummyRoot]) 
  extends NonRootNode(parents)

class TestUtil extends FlatSpec {

  "A RootNode" should "not have parents" in {
    val dummyRoot = new DummyRoot
    assert(dummyRoot.parents.isEmpty)
  }

  "A NonRootNode" should "have parents when constructed with them" in {
    val dummyRoot = new DummyRoot
    assert(dummyRoot.parents.isEmpty)
    val dummyNonRoot = new DummyNonRoot(List(dummyRoot))
    dummyRoot.addChild(dummyNonRoot)
    assert(dummyNonRoot.parents.contains(dummyRoot))
    assert(dummyRoot.children.contains(dummyNonRoot))
  }    
}

但是,我发现该 API 在第二次测试中有点笨拙。我不需要显式地将子节点添加到根节点,因为我已经指定了子节点的 parent 。我想从公共(public) API 中删除它,所以我的想法是修改 NonRootNode 的构造函数行为,为每个父级调用它。具体来说,我想写:

abstract class NonRootNode(override val parents: List[Hierarchical[_]])
  extends Hierarchical[NonRootNode] {

  //for each parent, add `this` to its children
  parents.map{p=>p.addChild(this)}
}

但是,当我添加此行时,出现以下错误:

Error:(19, 29) type mismatch;
 found   : NonRootNode
 required: Hierarchical[_$3]
  parents.map{p=>p.addChild(this)}

我不完全确定为什么会出现此编译器错误。我对Hierarchical[_]的理解是任何Hierarchical,但我可能会弄错。无论如何,我认为我已经接近我想要的行为了。我做错了什么?

最佳答案

Hierarchical[_] 并不意味着“任何分层”。它的意思是“某种未知的固定类型的层次结构”。

例如

def foo: Hierarchical[_] = new Hierarchical[Int] 

有效:它声明一个函数,该函数将返回一些Hierarchical的实现,调用者不知道其确切类型。这很好。

另一方面:

def bar(h: Hierarchical[String]) = doStuff(h)
bar(foo)

不起作用:函数bar需要一个精确类型Hierarchical[String]的参数,而传递给它的内容不能保证具有该类型,它的类型参数未知。

在您的情况下,.addChildHierarchical[T]的方法(其中T的值您未知),并想要一个相同类型的参数。但您传递给它的是Hierarchical[NonRootNode]。这是非法的,因为无法保证 NonRootNode 与(未知)T 相同。

关于scala - 为什么我不能在扩展通用特征的类中调用参数为 `this` 的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40450045/

相关文章:

scala - Scala 可以在参数中允许自由类型参数吗(Scala 类型参数是一等公民吗?)?

scala - 为什么在进程(字符串)之后需要一个空行!在斯卡拉?

ios - 通用 View Controller 无法与委托(delegate)和扩展一起使用

struct - Rust 特征状态

scala - 如何在Typesafe激活器中创建Eclipse Scala项目?

silverlight - 在其继承树中具有通用类的 UserControl

c# - C# 中泛型类型的缺点

rust - 是否有任何特征可以指定数字功能?

rust - 具有参数化关联类型的特征

scala - 折叠具有未知类型的 HList