You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala特质混入中的方法调用顺序技术问询

First, let's fix up your incomplete BasicIntQueue class so we can run and test behavior properly:

import scala.collection.mutable.ArrayBuffer

abstract class IntQueue { 
  def get(): Int 
  def put(x: Int) 
}

trait Doubling extends IntQueue{
  abstract override def put(x: Int) {
    println("In Doubling's put")
    super.put(2*x)
  }
}

trait Incrementing extends IntQueue {
  abstract override def put(x: Int) {
    println("In Incrementing's put")
    super.put(x + 1)
  }
}

class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]
  def get() = buf.remove(0)
  def put(x: Int) { 
    println("In BasicIntQueue's put")
    buf += x
  }
}

Now, the key to understanding method call order when mixing traits in Scala is linearization—Scala creates a linear inheritance chain from your base class and mixed-in traits, and super calls follow this chain in a specific order. Let's walk through two common scenarios:

Scenario 1: Mix Incrementing first, then Doubling

If you create an instance like this:

val queue = new BasicIntQueue with Incrementing with Doubling
queue.put(10)

Scala's linearization order here is:
Doubling → Incrementing → BasicIntQueue → IntQueue → AnyRef → Any

Here's what happens when you call put(10):

  1. We enter the last mixed-in trait first (Doubling): it prints "In Doubling's put", then calls super.put(2*10 = 20).
  2. Next, we move to the previous trait in the chain (Incrementing): it prints "In Incrementing's put", then calls super.put(20 + 1 = 21).
  3. Finally, we reach the base class (BasicIntQueue): it prints "In BasicIntQueue's put" and adds 21 to the buffer.

The output will look like:

In Doubling's put
In Incrementing's put
In BasicIntQueue's put

Scenario 2: Mix Doubling first, then Incrementing

Swap the order of traits when creating the instance:

val queue = new BasicIntQueue with Doubling with Incrementing
queue.put(10)

Now the linearization order flips to:
Incrementing → Doubling → BasicIntQueue → IntQueue → AnyRef → Any

The call sequence changes accordingly:

  1. First, we enter Incrementing (last mixed-in trait): prints "In Incrementing's put", calls super.put(10 + 1 = 11).
  2. Next, we move to Doubling: prints "In Doubling's put", calls super.put(2*11 = 22).
  3. Finally, BasicIntQueue handles the put: prints "In BasicIntQueue's put" and adds 22 to the buffer.

Output here is:

In Incrementing's put
In Doubling's put
In BasicIntQueue's put

Core Rules to Remember

  • Right-to-left linearization: When using with to mix multiple traits, the last trait you list gets top priority in the linear chain—super calls work their way leftward through the traits until they hit the base class.
  • abstract override is mandatory: This modifier lets a trait override an abstract method from the base class while still calling super, since the concrete implementation will come from the class/trait it's mixed into.
  • No duplicate calls: Linearization ensures each class/trait is only included once in the chain, so you don't get redundant method executions.

内容的提问来源于stack exchange,提问作者Mandroid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:48:59