【问题标题】:Why it is not possible to override mutable variable in scala?为什么不能在 scala 中覆盖可变变量?
【发布时间】:2015-07-14 05:31:30
【问题描述】:

为什么不能在 scala 中覆盖可变变量?

class Abs(var name: String){
}

class AbsImpl(override var name: String) extends Abs(name){
}

上面的代码给出了以下编译时错误:-

variable name cannot override a mutable variable

如果 name 声明为 val,那么上面的代码可以正常工作。

【问题讨论】:

  • 为什么有人要overridevar ?覆盖 var 是什么意思?
  • 因为覆盖它并没有多大意义。它是可变的,你可以改变它。压倒一切甚至意味着什么? stackoverflow.com/questions/16413986/…
  • @Sarvesh:感谢您的快速回复。我只是想了解,为什么允许 val ?
  • 因为 val 有一个固定值。当你覆盖它时你可以改变它。
  • @Falmarri 因为您可能需要构造函数的参数来设置此变量的值,并且 override 将让此参数与此变量具有完全相同的名称,因为它将是这个变量。到目前为止,您需要为这个参数想出一个新名称。我使用带有尾随下划线的 myvar_ 作为参数的约定,该参数将设置一个同名的 var,减去下划线,并且永远不应再次使用。

标签: scala inheritance overriding


【解决方案1】:

简短的回答:您需要将 -Yoverride-vars 传递给 Scala 编译器。

根据规范,var 既是 getter 也是 setter,正常的覆盖规则适用于这些方法。然而,事实证明这会产生一些不良后果。到 final 关键字和内联。编译器中的代码提到需要进行一些规范说明:

// TODO: this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here.
if (!settings.overrideVars)
  overrideError("cannot override a mutable variable")

相关票证:SI-3770

【讨论】:

    【解决方案2】:

    我相信其意图只是设置继承的var name 的值。这可以通过这种方式实现(没有override var):

    class Abs(var name: String){
    }
    
    class AbsImpl(name: String) extends Abs(name){
    }
    

    歧义源于AbsImpl 中的本地变量name: String,该变量以继承自Absvar name: String 命名。类似的代码,在语法上不那么模棱两可,但也不那么优雅:

    class Abs(var name: String){
    }
    
    class AbsImpl(name_value: String) extends Abs(name_value){
    }
    

    【讨论】:

      【解决方案3】:

      当你想要覆盖一个 var 时,它相当于试图覆盖 java 中的一个字段,这是不可能的。

      【讨论】:

        【解决方案4】:

        如果您可以使用 var 覆盖 var,则覆盖成员可以具有更窄的类型。 (这就是覆盖的定义。)

        然后你可以分配一个更宽类型的值,然后读取它期望更窄的类型,然后失败。

        相关设置器的说明:

        scala> class A ; class B extends A
        defined class A
        defined class B
        
        scala> abstract class C { var x: A } ; class D extends C { var x: B = _ }
        <console>:13: error: class D needs to be abstract, since variable x in class C of type A is not defined
        (Note that an abstract var requires a setter in addition to the getter)
               abstract class C { var x: A } ; class D extends C { var x: B = _ }
                                                     ^
        
        scala> abstract class C { var x: A }
        defined class C
        
        scala> class D extends C { var x: B = _ ; def x_=(a: A) = ??? }
        defined class D
        

        【讨论】:

        • 当你覆盖时,并不是你可以有一个“更窄的类型”。实际上,它覆盖了两个方法,getter 和 setter。第一个在 var 的类型中是协变的,第二个在 var 的类型中是逆变的,所以即使你要覆盖,类型也是不变的。
        • @MikaëlMayer 这是我演示的另一种说法,除了覆盖成员的定义以一致性而不是去糖开始。 scala-lang.org/files/archive/spec/2.11/…
        • 将 vars 解释为 getter 和 setter 是唯一受规范支持的解释。一致性关系不处理变量,只处理方法和 val,但变量被定义为“等价于”getter 和 setter。 scala-lang.org/files/archive/spec/2.11/…。我会说它应该被允许。相反,即使尝试通过 getter 和 setter 覆盖,它也是不允许的。谜团仍在继续。
        【解决方案5】:

        当您尝试覆盖的 var 已经有分配时,就会发生这种情况。我不确定为什么这是被禁止的,但也没什么意义。

        另见this question

        name 定义为抽象

        trait Abs {
          var name: String
        }
        
        class AbsImpl(name0: String) extends Abs {
          var name = name0
        }
        

        trait Abs {
          var name: String
        }
        
        class AbsImpl(private var name0: String) extends Abs {
          def name = {
            println("getter")
            name0
          }
        
          def name_=(value: String) = {
            println("setter")
            name0 = value
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2013-05-01
          • 2022-01-26
          • 2011-04-29
          • 2015-09-09
          • 1970-01-01
          • 2011-09-07
          • 2019-03-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多