为什么我不能在扩展通用特征的 class 中调用带有参数 `this` 的方法?
Why can't I call a method with parameter `this` in a class extending a generic trait?
我正在编写一个特征来描述层次结构(如图形)中的 node-like objects。我的工作代码如下:
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
}
我有一些反映这种行为的测试:
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 在第二个测试中有点笨拙。我不需要明确地向根节点添加 child,因为我已经指定了 child 的 parents。我想从 public API 中删除它,所以我的想法是修改 NonRootNode
的构造函数行为,以便为每个 parents 调用它。具体来说,我想写:
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[_]
parents.map{p=>p.addChild(this)}
我不完全确定为什么会出现此编译器错误。我对 Hierarchical[_]
的理解是 any Hierarchical
,但我可能错了。无论如何,我认为我已经接近我想要的行为了。我做错了什么?
Hierarchical[_]
并不意味着 "any Hierarchical"。意思是"a Hierarchical of some fixed type, that is unknown"。
例如
def foo: Hierarchical[_] = new Hierarchical[Int]
有效:它声明了一个函数,该函数将 return Hierarchical
的某些实现,调用者不知道其确切类型。这很好。
另一方面:
def bar(h: Hierarchical[String]) = doStuff(h)
bar(foo)
Does not work: function bar
想要一个确切类型的参数 Hierarchical[String]
,并且不能保证传递给它的东西有那个类型,它的类型参数是未知的。
在你的例子中,.addChild
是 Hierarchical[T]
的方法(其中 T
的值对你来说是未知的),并且需要一个相同类型的参数。但是你传递给它的是Hierarchical[NonRootNode]
。这是非法的,因为无法保证 NonRootNode
与(未知的)T
.
相同
我正在编写一个特征来描述层次结构(如图形)中的 node-like objects。我的工作代码如下:
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
}
我有一些反映这种行为的测试:
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 在第二个测试中有点笨拙。我不需要明确地向根节点添加 child,因为我已经指定了 child 的 parents。我想从 public API 中删除它,所以我的想法是修改 NonRootNode
的构造函数行为,以便为每个 parents 调用它。具体来说,我想写:
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[_]
parents.map{p=>p.addChild(this)}
我不完全确定为什么会出现此编译器错误。我对 Hierarchical[_]
的理解是 any Hierarchical
,但我可能错了。无论如何,我认为我已经接近我想要的行为了。我做错了什么?
Hierarchical[_]
并不意味着 "any Hierarchical"。意思是"a Hierarchical of some fixed type, that is unknown"。
例如
def foo: Hierarchical[_] = new Hierarchical[Int]
有效:它声明了一个函数,该函数将 return Hierarchical
的某些实现,调用者不知道其确切类型。这很好。
另一方面:
def bar(h: Hierarchical[String]) = doStuff(h)
bar(foo)
Does not work: function bar
想要一个确切类型的参数 Hierarchical[String]
,并且不能保证传递给它的东西有那个类型,它的类型参数是未知的。
在你的例子中,.addChild
是 Hierarchical[T]
的方法(其中 T
的值对你来说是未知的),并且需要一个相同类型的参数。但是你传递给它的是Hierarchical[NonRootNode]
。这是非法的,因为无法保证 NonRootNode
与(未知的)T
.