如何解决Scala中冲突成员的继承问题
我是Scala初学者。有人告诉我,“特质中的一个领域可以是具体的,也可以是抽象的” 当我运行上面的代码时,编译器输出了一些错误消息: " 类C2继承冲突成员: 字符串和类型的特征T2中的值f1 字符串类型的特征T3中的变量f1 (注意:这可以通过在C2类中声明重写来解决。) 类C2用T3{}扩展T2 " 那么,如果C2扩展了具有相同字段名的特征,那么应该改变什么呢?如何解决Scala中冲突成员的继承问题,scala,Scala,我是Scala初学者。有人告诉我,“特质中的一个领域可以是具体的,也可以是抽象的” 当我运行上面的代码时,编译器输出了一些错误消息: " 类C2继承冲突成员: 字符串和类型的特征T2中的值f1 字符串类型的特征T3中的变量f1 (注意:这可以通过在C2类中声明重写来解决。) 类C2用T3{}扩展T2 " 那么,如果C2扩展了具有相同字段名的特征,那么应该改变什么呢? 谢谢您的帮助。您可以手动解决歧义: trait T2 { val f1: String = "T2f1" }
谢谢您的帮助。您可以手动解决歧义:
trait T2 {
val f1: String = "T2f1"
}
trait T3 {
val f1: String = "T3f1"
}
class C2 extends T2 with T3 {
override val f1: String = "T2f1"
}
或
编译器可以通过线性化自动完成这项工作
trait T2 {
val f1: String = "T2f1"
}
trait T3 extends T2 {
override val f1: String = "T3f1"
}
class C2 extends T2 with T3
公认的答案是正确的,但请记住,所建议的模式很奇怪,在非平凡的情况下可能会导致难以理解的错误。根据我的经验,重写非抽象的
vals
只会给你带来麻烦
问题是初始化代码是已定义类/特征的构造函数的一部分。这意味着在创建C2
的实例时,将执行初始化T2.f1
和T3.f1
的代码:
trait T2 {
val f1: String = {
println("T2")
"T2f1"
}
}
trait T3 {
val f1: String = {
println("T3")
"T3f1"
}
}
class C2 extends T2 with T3 {
override val f1: String = {
println("C2")
"T3f1"
}
}
new C2 // Will print "T2", then "T3", then "C2"
如果初始化代码有任何重要的副作用,这可能会导致难以追踪错误!它还有一个缺点,就是迫使您在C2
中重复一些T3
的代码
如果您不一定需要T2.f1
和T3.f1
成为vals
,那么最好使用defs
来避免抽象的代码初始化vals
:
trait T2 {
def f1: String = "T2f1"
}
trait T3 {
def f1: String = "T3f1"
}
class C2 extends T2 with T3 {
override val f1: String = "C2f1" // You can keep this a def if you like
}
如果确实需要f1
作为val,例如,如果需要在模式匹配语句中使用稳定值,则可以使用以下选项:
trait T2 {
val f1: String
protected def computeF1: String = {
println("T2")
"T2f1"
}
}
trait T3 {
val f1: String
protected def computeF1: String = {
println("T3")
"T3f1"
}
}
class C2 extends T2 with T3 {
override val f1: String = computeF1 // You can keep this a def if you like
override protected def computeF1: String = super[T3].computeF1
}
new C2 // Only prints "T3" once
最后一个解决方案有点冗长,但它通过避免重写非抽象的
val
完全绕过了这个问题 建议的示例是正确的,但尽量避免循环依赖,这也可能导致一些严重问题
这里的问题是,您在trait中有相同的字段,而编译器无法解析要使用的trait的哪个属性。因此,您可以通过将问题显式化给编译器来解决问题
Trait A{
val x:String=“ABC”}
Trait B extends A{
override val x: String=“DEF”}
class AB extends B{
override val f1: String = super[T3].x}
类C2使用T3扩展T2{override val f1:String=…}
您的代码将无法编译。我只是想解释一下这些建议。这些都有助于进一步的学习。非常感谢。
trait T2 {
val f1: String
protected def computeF1: String = {
println("T2")
"T2f1"
}
}
trait T3 {
val f1: String
protected def computeF1: String = {
println("T3")
"T3f1"
}
}
class C2 extends T2 with T3 {
override val f1: String = computeF1 // You can keep this a def if you like
override protected def computeF1: String = super[T3].computeF1
}
new C2 // Only prints "T3" once
Trait A{
val x:String=“ABC”}
Trait B extends A{
override val x: String=“DEF”}
class AB extends B{
override val f1: String = super[T3].x}