【问题标题】:Must override val variable in scala必须在 scala 中覆盖 val 变量
【发布时间】:2011-09-07 14:43:19
【问题描述】:

我在 scala 中遇到了一个奇怪的问题。以下是我的代码,Employee类扩展了Person类

但是这段代码无法编译,我已经明确定义了 firstName 和 lastName 作为 val 变量。这是为什么 ?这是否意味着我必须覆盖基类中的 val 变量?目的是什么?

class Person( firstName: String,  lastName: String) {

}

class Employee(override val firstName: String, override val lastName: String, val depart: String)
    extends Person(firstName,lastName){

} 

【问题讨论】:

    标签: scala


    【解决方案1】:

    除非我误解了你的意图,否则这里是扩展 Person 的方法。

    Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_21).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> class Person( firstName: String, lastName: String)
    defined class Person
    
    scala> class Employee(firstName: String, lastName: String, depart: String) extends Person(firstName, lastName)
    defined class Employee
    

    【讨论】:

      【解决方案2】:

      由于构造函数参数在 Person 中没有 val/var 声明,并且由于 Person 不是 case 类,所以参数不会是 Person 类的成员,而只是构造函数参数。编译器本质上是在告诉你:嘿,你说,firstName 和 lastName 是成员,它们覆盖/重新定义从基类继承的东西 - 但据我所知,没有什么......

      class Person(val firstName: String, val lastName: String)
      class Employee(fn: String, ln: String, val salary: BigDecimal) extends Person(fn, ln)
      

      顺便说一句,您不需要在此处将 firstName/lastName 声明为覆盖。只需将值转发给基类的构造函数即可。

      【讨论】:

        【解决方案3】:

        构造函数的输入参数不是 val,除非你说它们是。如果它们已经存在,为什么要覆盖它们?

        class Person(val firstName: String, val lastName: String) {}
        class Strange(
          override val firstName: String, override val lastName: String
        ) extends Person("John","Doe") {}
        class Employee(fn: String, ln: String, val depart: String) extends Person(fn,ln) {}
        

        如果它们不是 vals 并且您想制作 vals,则无需覆盖:

        class Person(firstName: String, lastName: String) {}
        class Employee(
          val firstName: String, val lastName: String, val depart: String
        ) extends Person(firstName,lastName) {}
        

        【讨论】:

        • 这个答案用一个问题来回答这个问题。我将尝试回答。您必须在 Strange 类中的 val 前面说 override 的原因是告诉编译器您不打算引入新字段。 override 大致意思是“在这里我声明了一些已经在父类中声明的东西,并且不打算引入一些不是继承的东西”。没有“覆盖”val 意味着“请创建一个公共的只读字段”。但是 Scala 不允许两个 val 字段具有相同的名称。因此override 是强制性的。
        • @TheodoreNorvell - 我的意思应该是,如果您只是要使用相同的字段扩展原始类,那么没有理由 创建覆盖。只需将它们作为参数传入,让超类 vals 成为 vals。
        • @RexKerr 好的,这很好。你在问,“为什么有override val?”;我在回答,“既然你有val,为什么还要override?”。在我正在编写的代码中,我遇到了类似的情况,但是在我的例子中,子类是一个案例类,因此构造函数参数自动是一个 val。在这种情况下,除非override 关键字在其中,否则编译器会给出错误消息,并且可能出于语法原因,它还需要val 关键字。唯一的缺点是这两个额外的单词,并且该字段被初始化了两次。
        • @TheodoreNorvell - 很公平——案例类是使用它的理由。
        • 正如我提到的,我有一个案例类。基本上我有sealed abstract class Command(val coord : Coord) ; case class Assignment(lhs : Expr, rhs : Expr, override val coord : Coord) extends Command(coord); ... 和许多其他案例。更好的方法是为构造函数提供 2 个参数列表,如下所示:sealed abstract class Command(val coord : Coord) ; case class Assignment(lhs : Expr, rhs : Expr)(coord : Coord) extends Command(coord); ...。在第二个参数列表中,参数不会自动变成val字段。
        【解决方案4】:

        你也可以考虑尽可能地重新设计你的超类作为特征。示例:

        trait Person {
          def firstName: String
          def lastName: String
        }
        
        class Employee(
          val firstName: String,
          val lastName: String,
          val department: String
        ) extends Person
        

        甚至

        trait Employee extends Person {
          def department: String
        }
        
        class SimpleEmployee(
          val firstName: String,
          val lastName: String,
          val department: String
        ) extends Employee
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-12
          • 1970-01-01
          • 2013-05-01
          • 1970-01-01
          相关资源
          最近更新 更多