问题
I have a scenario with multiple traits inheriting from a fixed base trait. The base trait has an abstract method that each needs to implement. The class using these traits also needs to implement this method:
trait A {
def f: Any
}
trait B1 extends A {
val i: Int
override def f: Any = println("B1: " + i)
}
trait B2 extends A {
val j: Int
override def f: Any = println("B2: " + j)
}
class C extends A with B1 with B2 {
val i = 1
val j = 2
override def f: Any = {
super.f
println("C::f")
}
}
Then when I do a
new C().f
It only outputs "B1: 1" and not "B2: 2"
Is there a way I can define B1, B2 and C so that all implementations of f can be called?
回答1:
Well as you know which two diamond traits you mix in, you can call both super implementations and specify the trait from which you want to call each super implementation.
So, you could implement C
like this:
class C extends A with B1 with B2 {
val i = 1
val j = 2
override def f: Any = {
super[B1].f
super[B2].f
println("C::f")
}
}
And would get the output:
B1: 1
B2: 2
C::f
回答2:
This is an example of the diamond problem which Scala addresses by the process of linearisation:
Scala resolves method names using a right-first depth-first search of extended 'traits', before eliminating all but the last occurrence of each module in the resulting list. So, the resolution order is: [D, C, A, B, A], which reduces down to [D, C, B, A].
so the output should be in your case
B2: 2
C::f
so it seems it is not possible to call all the f
overrides in both B1
and B2
, instead only B2.f
is resolved.
来源:https://stackoverflow.com/questions/57241306/how-to-have-multiple-traits-of-same-base-trait-implement-the-same-method