我是Scala的初学者。我被告知"特质中的一个字段可以是具体的或抽象的"。
trait T2 {
val f1: String = "T2f1"
}
trait T3 {
val f1: String = "T3f1"
}
class C2 extends T2 with T3{}
object Test2 extends App {
val c2 = new C2
println(c2.f1)
}
当我运行上面的代码时,编译器会打印一些错误消息:
" C2类继承冲突成员: 字符串中的值为f1,类型为String和 变量f1在String类型的特征T3中 (注意:这可以通过在C2类中声明覆盖来解决。) C2类延伸T2与T3 {} "
那么如果C2扩展具有相同字段名称的特征,应该改变什么? 谢谢你的帮助。
答案 0 :(得分:1)
您可以手动解决歧义:
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 {
val f1: String = "T3f1"
}
class C2 extends T2 with T3 {
override val f1: String = "T3f1"
}
编译器可以通过线性化自动执行此操作(如果它是
) trait T2 {
val f1: String = "T2f1"
}
trait T3 extends T2 {
override val f1: String = "T3f1"
}
class C2 extends T2 with T3
答案 1 :(得分:1)
接受的答案是正确的,但请记住,建议的模式很奇怪,并且可能导致在非平凡的情况下难以理解的错误。根据我的经验,覆盖非抽象vals
只会让您遇到麻烦。
问题是初始化代码是已定义的类/特征的构造函数的一部分。这意味着在创建T2.f1
的实例时,将执行初始化T3.f1
和C2
的代码:
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"
如果初始化代码有任何重要的副作用,这可能会导致难以追踪的错误!它还有一个缺点,就是强迫你在T3
中重复一些C2
的代码。
如果您绝对不需要T2.f1
和T3.f1
为vals
,那么最好使用defs
来避免在abstract {{{{}}中初始化代码1}}:
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
}
成为val,例如,如果你需要一个稳定的值来在模式匹配语句中使用它,你可以使用以下内容:
f1
这最后的解决方案有点冗长,但它通过避免覆盖非抽象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
来完全绕过问题。
答案 2 :(得分:0)
建议的例子是正确的,但尽量避免循环依赖,它也可能导致一些严重的问题。
这里看到的问题是你在这两个特征中都有相同的字段,编译器无法解析你要使用哪个特性的属性。因此,您可以通过使其明确编译器来解决问题。
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}