Дублированы ли аргументы конструктора Scala? - PullRequest
5 голосов
/ 06 сентября 2011

Я только что наткнулся на какую-то ситуацию, которая кажется мне странной.Я вполне мог бы упустить очевидное здесь - в любом случае, пожалуйста, помогите мне.

Рассмотрим следующий скрипт Scala Repl:

scala> class X(val s: String) { def run=println("(X): "+s) }
defined class X

scala> class Y(s: String) extends X("MY "+s) { override def run=println("(Y): "+s) }
defined class Y

scala> new Y("fish").run
(Y): fish

В этом скрипте я определяю класс X сатрибут класса "val s".Затем я определяю класс Y, который должен принимать один аргумент конструктора и передавать его в X-, что он и делает.Чтобы показать разницу, я изменяю «s» перед тем, как передать его X («MY» + s).

Наконец, я создаю новый Y и вызываю «run».Это выводит «fish» на консоль, поэтому очевидно, что атрибут «s» класса «X» был затенен новым атрибутом «s», который я создал в «Y».

Я пробовал это в Scala 2.8и 2.9.1 с тем же результатом.

Это должно быть так?Что мне делать, если я просто хочу передать аргументы конструктора из моего класса в суперкласс и не хочу сам сохранять параметр внутри дочернего класса?Какова общая практика здесь?

Спасибо!

Ответы [ 2 ]

8 голосов
/ 06 сентября 2011

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

Классы, показывающие примеры:

class X(val s: String) { def run=println("(X): "+s) }
class Y(s: String) extends X("MY "+s) { override def run=println("(Y): "+s) }
class Z(s0: String) extends X("MY "+s0) { override def run=println("(Z): "+s) }

Байт-код, показывающий нехватку памяти (только конструкторы):

// Note putfield to store s
public X(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #11; //Field s:Ljava/lang/String;
   5:   aload_0
   6:   invokespecial   #43; //Method java/lang/Object."<init>":()V
   9:   return

// Note putfield to store new s (then eventually calls X's constructor)
public Y(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #29; //Field s:Ljava/lang/String;
   5:   aload_0
   6:   new #16; //class scala/collection/mutable/StringBuilder
   9:   dup
   10:  invokespecial   #19; //Method scala/collection/mutable/StringBuilder."<init>":()V
   13:  ldc #40; //String MY 
   15:  invokevirtual   #25; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
   18:  aload_1
   19:  invokevirtual   #25; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
   22:  invokevirtual   #33; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
   25:  invokespecial   #44; //Method X."<init>":(Ljava/lang/String;)V
   28:  return

// Note - no putfield!
public Z(java.lang.String);
  Code:
   0:   aload_0
   1:   new #14; //class scala/collection/mutable/StringBuilder
   4:   dup
   5:   invokespecial   #17; //Method scala/collection/mutable/StringBuilder."<init>":()V
   8:   ldc #39; //String MY 
   10:  invokevirtual   #23; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
   13:  aload_1
   14:  invokevirtual   #23; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
   17:  invokevirtual   #32; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
   20:  invokespecial   #43; //Method X."<init>":(Ljava/lang/String;)V
   23:  return
1 голос
/ 07 сентября 2011

Действительно, параметр s скрывает параметр суперкласса.Важным моментом является то, что область действия параметра класса (т.е. параметра первичного конструктора) составляет всего класса .Итак, в вашем методе Y.run нет сомнений в том, что s относится к Ys

Это означает, что s должно быть сохранено в поле, и, как показал вам Рекс, это именно то, что происходит.,

Для параметра основного конструктора есть три варианта:

  • var => создает поле, получатель и установщик
  • val => создает поле и получатель
  • none => создает поле, если необходимо (т. Е. Параметр, используемый в методах), но не получает / устанавливает
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...