Почему невозможно переопределить изменяемую переменную в scala?
Почему невозможно переопределить изменяемую переменную в scala?
class Abs(var name: String){
}
class AbsImpl(override var name: String) extends Abs(name){
}
Выше кода дает следующую ошибку времени компиляции: -
variable name cannot override a mutable variable
Если имя объявлено val, тогда код выше работает нормально.
Ответы
Ответ 1
Если вы можете переопределить 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
Ответ 2
Короткий ответ: вам нужно передать -Yoverride-vars
компилятору Scala.
Согласно спецификации, a var
- это как получатель, так и сеттер, и для этих методов применяются нормальные правила переопределения. Однако это показало, что некоторые нежелательные последствия w.r.t. к ключевому слову 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
Ответ 3
Я считаю, что целью было просто установить значение унаследованного var name
. Это может быть достигнуто таким образом (без override var
):
class Abs(var name: String){
}
class AbsImpl(name: String) extends Abs(name){
}
Неоднозначность возникает из локального var name: String
в AbsImpl
, который назван в честь унаследованного var name: String
из Abs
. Аналогичный код, менее синтаксически неоднозначный, но также менее элегантный, будет:
class Abs(var name: String){
}
class AbsImpl(name_value: String) extends Abs(name_value){
}
Ответ 4
Это происходит, когда var
, который вы пытаетесь переопределить, уже имеет назначение. Я не уверен, почему это запрещено, но и это мало смысла.
См. также этот вопрос.
Определите 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
}
}
Ответ 5
Если вы хотите переопределить var, это эквивалентно попытке переопределить поле в java, что невозможно.