Вопрос по инициализации класса абстрактного типа в scala
Я определяю класс с абстрактным типом следующим образом:
abstract class AbsCell2{
type T
val init: T
private var value: T = {
println("Hello "+init);
init
}
def get : T = value
def set(x : T) = { value = x}
}
Теперь я создаю экземпляр объекта с типом Int
scala> val cell = new AbsCell2{type T = Int ; val init = 10}
Hello 0
cell: AbsCell2{type T = Int} = $anon$1@969ebb
Обратите внимание на вывод из println
, Это швы переменной init
не был инициализирован как 10. Обратите внимание, что версия scala - 2.9.0-1.
3 ответа
Я думаю, что вы ищете ранние инициализаторы Scala,
scala> val cell = new {type T = Int ; val init = 10} with AbsCell2
Hello 10
cell: AbsCell2{val init: Int; type T = Int} = $anon$1@1efa9557
scala> cell.get
res0: cell.T = 10
Ранние инициализаторы позволяют вам выделить новый объект и задать некоторые конкретные поля перед запуском конструктора класса. В этом случае, так как value
зависит от init
мы используем ранний синтаксис инициализатора (new { val init = ... } with AbsCell2
) к первому набору init
так что конструктор класса может правильно инициализировать value
,
Смотрите также этот вопрос: что такое "ранний инициализатор" в Scala?
Изменить с val на def:
abstract class AbsCell2{
type T
def init: T
private var value: T = {
println("Hello "+init);
init
}
def get : T = value
def set(x : T) = { value = x}
}
Работает как положено:
scala> val cell = new AbsCell2{type T = Int ; def init = 10}
Hello 10
cell: AbsCell2{type T = Int} = $anon$1@4302df5
На вопрос о разнице между new { type T = Int ; val init = 10 }
с AbsCell2 и new AbsCell2 { type T = Int ; val init = 10 }
,
Первый - это так называемые ранние инициализаторы или предварительно инициализированные поля (упомянутые в главе "Абстрактные члены" в Программирование в Scala). Это позволяет подклассу инициализировать поля до вызова суперкласса. В этом случае init уже был установить как 10 до инициализации AbsCell2。
Последний является нормальным наследованием, он создает анонимный класс, затем расширяет AbsCell2, как:
class AbsCell' extends AbsCell {
type T = Int
val init = 10
}
Однако анонимный класс инициализируется после абстрактного класса AbsCell2, поэтому init не доступны при самой инициализации, а именно init является значением по умолчанию Type, в данном случае 0. Таким образом, вы получаете 0 в печати。
использование scalac -Xprint:all Test.scala
, вы увидите следующее:
abstract class AbsCell2 extends Object {
<stable> <accessor> def init(): Object;
....
def <init>(): AbsCell2 = {
AbsCell2.super.<init>();
AbsCell2.this.value = {
scala.this.Predef.println("Hello ".+(AbsCell2.this.init()));
AbsCell2.this.init()
};
()
}
};
// normal initialization
final class anon$1 extends AbsCell2 {
private[this] val init: Int = _;
<stable> <accessor> def init(): Int = anon$1.this.init;
....
def <init>(): <$anon: AbsCell2> = {
anon$1.super.<init>();
anon$1.this.init = 10;
()
}
};
// early initialization
final class anon$2 extends AbsCell2 {
private[this] val init: Int = _;
<stable> <accessor> def init(): Int = anon$2.this.init;
....
def <init>(): <$anon: AbsCell2> = {
val init: Int = 10;
anon$2.this.init = init;
anon$2.super.<init>();
()
}
}
Из кода видно, что для нормальной инициализации init устанавливается в 3 после инициализации суперкласса AbsCell2, когда вызывается AbsCell2.this.init(), он фактически ссылается на поле инициализации подкласса, а 3 еще предстоит установить, так что мы получаем значение типа по умолчанию early Напротив, для ранней инициализации сначала установите init в 3, а затем вызовите инициализацию суперкласса。