2015-07-14 5 views
13

Почему в scala нельзя переопределить изменяемую переменную?Почему в scala нельзя переопределить изменяемую переменную?

class Abs(var name: String){ 
} 

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

Приведенный выше код дает следующие компиляции ошибки времени: -

variable name cannot override a mutable variable

Если имя объявляется вал, то выше код работает отлично.

+0

Почему кто-то хочет «переопределить» 'var'? В чем смысл переопределения var? –

+0

Потому что переопределение этого не имеет особого смысла. Он изменчив, вы можете просто изменить его.Что означает переопределение? http://stackoverflow.com/questions/16413986/how-to-override-a-mutable-variable-in-trait-in-scala – Falmarri

+0

@Sarvesh: Спасибо за ваш быстрый ответ. Я просто пытаюсь понять, почему это разрешено для val? – mogli

ответ

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 
+0

Когда вы переопределяете, это не значит, что у вас может быть «более узкий тип». Фактически, он переопределяет два метода: геттер и сеттер. Первый из них является ковариантным по типу var, второй является контравариантным по типу var, поэтому, даже если вы должны переопределить, тип будет инвариантным. –

+0

@ MikaëlMayer Это еще один способ сказать то, что я продемонстрировал, за исключением того, что определение переопределяющего элемента начинается с соответствия, а не с десурагированием. http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#overriding –

+0

Интерпретация варов как геттера и сеттера является единственной, которая поддерживается спецификацией , Соотношение соответствия не обрабатывает переменные, только методы и vals, но переменные определяются как «эквивалентные» для геттера и сеттера. http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#variable-declarations-and-definitions. Я бы сказал, что это должно быть разрешено. Вместо этого он запрещен, даже если вы пытаетесь переопределить через геттер и сеттер. Тайна продолжается. –

0

Это происходит, когда 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 
    } 
} 
1

Я считаю, что намерение было просто установить значение наследственного var name. Это может быть достигнуто таким образом (без override var):

class Abs(var name: String){ 
} 

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

Неоднозначность возникает из локальной вар name: String в AbsImpl, который назван в честь унаследованный var name: String от Abs. Аналогичный код, менее синтаксически неоднозначным, но и менее элегантно будет:

class Abs(var name: String){ 
} 

class AbsImpl(name_value: String) extends Abs(name_value){ 
} 
2

Короткий ответ: вам нужно передать -Yoverride-vars компилятору Scala.

Согласно спецификации, var является как получателем, так и сеттером, и для этих методов применяются нормальные правила переопределения. Однако это показало, что некоторые нежелательные последствия w.r.t. к ключевому слову final и inlining. Код в компиляторе упоминает необходимо будет некоторые спецификации уточнений:

// 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

+0

Я не был уверен, 'class C {def c = 42; def c _ = (x: Int): Unit =()}; (новый C): {var c: Int} 'будет работать. Кто-то недавно был удивлен «классом C {val c = 42}; (новый C) .c_'. Возможно, спецификация должна явно их унифицировать. Я вижу, что я не могу 'class C {var c: Any = _}; класс D расширяет C {переопределяет var c: Int = 42; def c_ = (x: Any) = c_ = (x.toString.toInt)} 'по крайней мере, не на моем перерыве на обед. –

0

Если вы хотите, чтобы переопределение Var его эквивалент пытается переопределить поля в Java, который не возможно ,

Смежные вопросы