超链接Scala特征的行为

时间:2011-10-08 03:26:41

标签: scala traits

为什么以下x.func会返回"B extends B extends B"? 如何安排此代码以便它返回"B extends A extends Base"

trait Base {
  def name = "Base"
  def func = name
}

trait A extends Base {
  override def name = "A"
  override def func = name + " extends " + super.func
}

trait B extends Base {
  override def name = "B"
  override def func = name + " extends " + super.func
}

val x = new Base with A with B
println(x.func)

更新:一种安排如下。它现在func1A中的B具有相同的定义。如果我尝试将其移动到Derived类,它就不起作用。任何想法如何删除重复func1

trait Base {
  def name = "Base"
  def func1(s: String) = s
}

trait Derived extends Base {
  def func = func1(name)
}

trait A extends Derived {
  override def func1(s: String) = s + " extends " + super.func1(super.name)
  override def name = "A"
}

trait B extends Derived {
  override def func1(s: String) = s + " extends " + super.func1(super.name)
  override def name = "B"
}

val x = new Base with A with B
println(x.func)

1 个答案:

答案 0 :(得分:10)

我认为继承令可能实际上是你正在寻求的。如果将" extends "替换为显示调用哪种特征的方法:

trait Base {
  def name = "Base"
  def func = "Base." + name
}

trait A extends Base {
  override def name = "A"
  override def func = name + " A.extends " + super.func
}

trait B extends Base {
  override def name = "B"
  override def func = name + " B.extends " + super.func
}

val x = new Base with A with B
println(x.func)
// B B.extends B A.extends Base.B

只是name总是"B"。换句话说:

trait Base { def func = "Base" } 
trait A extends Base { override def func = "A extends " + super.func }
trait B extends Base { override def func = "B extends " + super.func }
val x = new Base with A with B
println(x.func)
// B extends A extends Base

这就是你想要的......

您的示例的完全线性化是:

Object, B, A, Base, ScalaObject, AnyRef, Any

(有关如何计算线性化的实用解释,请参阅http://ofps.oreilly.com/titles/9780596155957/ScalaObjectSystem.html#Linearization

编辑以回答评论:为什么name始终返回"B"?这是因为特征def name会覆盖B方法以返回"B"。这是继承的全部要点,能够在子类中精炼的超类行为中使用:

trait Legs { 
  def legs: Int 
  def printLegs() { println("I have " + legs + " legs") }
}

class Dog extends Legs { def legs = 4 }
class Chicken extends Legs { def legs = 2 }

new Dog printLegs
// I have 4 legs
new Chicken printLegs
// I have 2 legs
特征legs中的{p> Legslegs中的Dog不是一个独立的,具体取决于您是否在Legs或{{1}中引用它}同样,如果您的对象是Dog,则def name将始终返回"B"

看起来你想使用name作为私有方法:

B

我发现如果没有清晰的对象模型,使用特征和继承会很快变得复杂。我假设您清理/简化了示例以使用trait Base { private def _name() = "Base" def func = _name } trait A extends Base { private def _name() = "A" override def func = _name + " extends " + super.func } trait B extends Base { private def _name() = "B" override def func = _name + " extends " + super.func } val x = new Base with A with B println(x.func) // B extends A extends Base 这样的通用名称,以便您了解问题的核心,但另一方面,它并没有给我任何有关您可以做什么更改的见解它适合你。正如您所说,我已经安排了代码,以便打印A, B, Base, func。我确信还有一些其他约束不在为什么它对你不起作用。