链式 Scala 特征中 super 的行为

发布于 2024-12-08 16:04:29 字数 1079 浏览 1 评论 0原文

为什么下面的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)

更新:一种安排可能如下。现在,AB 中的 func1 具有相同的定义。如果我尝试将其移动到 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)

Why does x.func below return "B extends B extends B"?
How to arrange this code so that it returns "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)

Update: One arrangement could be as follows. It now has identical definitions of func1 in A and B. It does not work if I try to move it to the Derived class. Any ideas how to remove the repetition of 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心凉怎暖 2024-12-15 16:04:29

我认为继承顺序实际上可能就是您所寻求的。如果将 " 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 有关如何计算出的实用说明线性化)

编辑回答评论:为什么名称总是返回“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 中的 legs 并不是一个独立于 legs< 的行为。 Dog 中的 /code> 取决于您在 LegsDog 中引用它...同样,您的 def name 将始终返回 "B"如果您的对象是 B

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

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 之类的通用名称,以便您了解问题的核心,但另一方面,它没有给我任何信息关于您可以进行哪些更改以使其适合您的见解。正如您所问,我已经安排了代码,以便它打印“B extends A extends Base”。我确信还有很多其他限制不属于它为什么不适合您的问题。

I think the inheritance order may actually be the one your are seeking. If you replace the " extends " with one that shows which method of which trait is called:

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

It's just that name is always "B". In other words:

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

which is what you want...

The full linearization of your example is:

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

(see http://ofps.oreilly.com/titles/9780596155957/ScalaObjectSystem.html#Linearization for a practical explanation on how to figure out the linearization)

Edit to answer comment: why is the name always returns "B"? That's because the def name method is overridden by the trait B to return "B". That's the whole point of inheritance, to be able to use in superclasses behavior that is refined in subclasses:

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 in trait Legs is not a separate one than legs in Dog depending on if you refer to it in Legs or Dog... Similarly, your def name will always return "B" if your object is a B.

It looks like you want to use name as a private method:

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

I find that if there isn't a clear object model, using trait and inheritance quickly gets complicated. I assume you sanitized/simplified the example to use generic names like A, B, Base, func so that you get to the core of the issue, but on the other hand it doesn't give me any insights on what changes you could do to make it work for you. As you asked I've arrange the code so that it prints "B extends A extends Base". I'm sure there are a bunch of other constraints that aren't in the question why it won't work for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文