Вопрос по инициализации класса абстрактного типа в scala - PullRequest
4 голосов
/ 14 августа 2011

Я определяю класс с абстрактным типом следующим образом:

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 ]

4 голосов
/ 14 августа 2011

Я думаю, что вы ищете ранние инициализаторы 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?

0 голосов
/ 11 июля 2015

На вопрос о разнице между 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 (), он фактически ссылается на поле init подкласса и 3 еще предстоит установить, поэтому мы получаем значение типа по умолчанию. Напротив, при ранней инициализации сначала устанавливают значение init 3, а затем вызывают инициализацию суперкласса 6

0 голосов
/ 04 ноября 2011

Изменить с 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...