Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 与冲突成员混合的Trait:为什么我的代码可以成功编译?_Scala_Oop - Fatal编程技术网

Scala 与冲突成员混合的Trait:为什么我的代码可以成功编译?

Scala 与冲突成员混合的Trait:为什么我的代码可以成功编译?,scala,oop,Scala,Oop,对不起,这个问题可能有点长,因为我想尽可能准确地描述问题和我的理解 最近我在学习Scala的特质系统 我做了一些关于冲突成员的实验,请参见以下代码: trait TA { def play() = println("TA play") } trait TB { def play() = println("TB play") } trait TC { def play() = println("TC play") } c

对不起,这个问题可能有点长,因为我想尽可能准确地描述问题和我的理解

最近我在学习Scala的特质系统

我做了一些关于冲突成员的实验,请参见以下代码:

trait TA {
  def play() = println("TA play")
}

trait TB {
  def play() = println("TB play")
}

trait TC {
  def play() = println("TC play")
}

class MyClass extends TA with TB with TC {
}
当然,这段代码编译失败了:

Error:(13, 8) class MyClass inherits conflicting members:
  method play in trait TB of type ()Unit  and
  method play in trait TC of type ()Unit
(Note: this can be resolved by declaring an override in class MyClass.)
class MyClass extends TA with TB with TC {
      ^
我的理解是

MyClass
的线性化是
{MyClass,TC,TB,TA}
,但是由于
TB的
play
TC
play
上没有
覆盖
,因此编译失败

一种解决方法是在
TA
TB
TC
上标记
override
,如下所示:

trait IPlay {
  def play()
}

trait TA extends IPlay {
  override def play() = println("TA play")
}

trait TB extends IPlay {
  override def play() = println("TB play")
}

trait TC extends IPlay {
  override def play() = println("TC play")
}

class MyClass extends TA with TB with TC {
}
好的,这段代码可以按预期成功编译

但是这个呢:

trait TA {
  def play() = println("TA play")
}

trait TB {
  def play() = println("TB play")
}

trait TC {
  def play() = println("TC play")
}

class MyClass extends TA with TB with TC {
  override def play(): Unit = {
    println("MyClass play")
    super.play()
    super[TC].play()
    super[TA].play()
    super[TB].play()
  }
}

(new MyClass).play()

// -- Output:
// MyClass play
//   TC play
//   TC play
//   TA play
//   TB play
令我惊讶的是,这段代码也可以成功编译

class
MyClass
的线性化仍然是
{MyClass,TC,TB,TA}
,在
TB
play
TC
play
上没有
override
,唯一的区别是我在
MyClass
play
上添加了
override

为什么可以成功编译

请注意,Scala不是Java或C#,没有冲突成员的默认行为

在Java中,如果不将方法标记为
@Override
,则默认行为为Override

在C#中,如果不将方法标记为
覆盖
,则默认行为是隐藏

在Scala中,如果您没有将方法标记为
覆盖
,则没有默认行为,它们应该是冲突成员,IMO

因此,我认为上面的代码编译应该失败,但为什么它可以成功呢

或者我的理解是错误的


非常感谢。

您已经在子类中手动定义了行为。 你为什么感到惊讶?在这种情况下,什么是不正确的

我认为这个例子中最让人困惑的地方是“super.play()”是合法的,并且与最后一个继承的成员TC有关。我认为这只是一个解决办法,当我们只是采取最后一个。
我想他们可以通过这种变通方法解决第一种情况(不编译),只需使用最后一个继承的实现。

也要了解潜在冲突的来源,我们需要采用
MyClass
的“观点”

让我们回顾一下你的例子,看看你为什么会得到这些结果(为了简化,我将使用2个特征,而不是3个)

第一个例子:通常的冲突
trait TA{def play()=println(“TA”)}
特征TB{def play()=println(“TB”)}
类MyClass使用TB{}扩展TA
这失败了,因为这两个特征定义了一个具有相同签名的
play
方法,但不清楚为
MyClass.play
选择哪个方法。有人可能会说“编译器可以选择TB.play,因为它是最后一个混合的trait”,但由于没有声明重写某些内容的意图,Scala拒绝了它。原则上它可以工作,但Scala团队选择迫使您更清楚地表达您的意图。

怎么做

明确意图1:在特质上超越
trait T{def play():Unit}
trait TA{override def play()=println(“TA”)}
trait TB{override def play()=println(“TB”)}
类MyClass使用TB{}扩展TA
第二个示例显示了表示覆盖意图的一种方式。由于
TA.play
TB.play
是用
override
声明的,因此很明显,它们打算覆盖范围内的方法
play():Unit
。这就是为什么编译器允许
TB.play
MyClass
中“替换”
TA.play

明确意图2:在类中重写
class MyClass用TB扩展TA{
覆盖def播放():单位={
super.play()//super[TB].play()
超级[TA].play()
}
}
重写类中的方法是解决问题的另一种方法。这里我们确切地知道什么是
MyClass.play
,因为它是显式定义的。从
MyClass
的角度来看,没有歧义

编译器可以使用
super[TA].play()
,因为调用的方法很清楚:在
trait TA
中由
def play()=println(“TA”)
定义的方法。因此
super[TA].play()
将执行
println(“TA”)


super.play()
没有那么明确,但是类组成的规则很清楚:
super
在这个上下文中指的是最后一个mixin,也就是说,它与
super[TB]

在最后一个类中显式重写并手工选择要调用的实现相同。这显然是合法的。这就是mixin的工作原理。@texasbruce但我只是在最后一个类中重写,
TB
中的
play
方法,
TB
TC
仍然冲突。换句话说,在mixin之后,方法
play
TA
TB
TC
中的语义是什么?它们是
覆盖
隐藏
未定义
?令我惊讶的是,为什么我不需要在
TB
TC
中标记
覆盖
?在
TB
TC
MyClass
中方法
play
的语义是什么?它们是
不同的方法
覆盖
隐藏
未定义
冲突
?您说过“我想他们可以通过此解决方法解决第一种情况(未编译)”。我不这么认为,因为正如我在问题中所说的,Scala中没有冲突成员的默认行为。如果Scala像Java一样有默认的
override
行为,那么您是对的