如何解决Scala

时间:2018-04-08 08:00:22

标签: scala

我是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扩展具有相同字段名称的特征,应该改变什么? 谢谢你的帮助。

3 个答案:

答案 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

Conflicting fields in Scala Traits

答案 1 :(得分:1)

接受的答案是正确的,但请记住,建议的模式很奇怪,并且可能导致在非平凡的情况下难以理解的错误。根据我的经验,覆盖非抽象vals只会让您遇到麻烦

问题是初始化代码是已定义的类/特征的构造函数的一部分。这意味着在创建T2.f1的实例时,将执行初始化T3.f1C2的代码:

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.f1T3.f1vals,那么最好使用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}