Параметры конструктора scala по умолчанию имеют значение private val?

128

Я пытался:

class Foo(bar: Int)

против:

class Foo(private val bar: Int)

и они, кажется, ведут себя одинаково, хотя я не мог найти нигде, говорящего, что (bar: Int)расширяется до, (private val bar: Int)поэтому мой вопрос: идентичны ли они / похожи?

Кстати, я пытался использовать -Xprint:typerэти фрагменты кода, и они производят тот же код, за исключением дополнительной строки во втором. Как мне прочитать эту лишнюю строчку?

..
class Foo extends scala.AnyRef {
  <paramaccessor> private[this] val bar: Int = _;
  def <init>(bar: Int): this.Foo = {
    Foo.super.<init>();
    ()
  }
}
..


..
class Foo extends scala.AnyRef {
  <paramaccessor> private[this] val bar: Int = _;
  <stable> <accessor> <paramaccessor> private def bar: Int = Foo.this.bar;
  def <init>(bar: Int): this.Foo = {
    Foo.super.<init>();
    ()
  }
}
..
никто
источник

Ответы:

177

bar: Int

Это едва ли параметр конструктора. Если эта переменная не используется нигде, кроме конструктора, она остается там. Поле не создается. В противном случае private val barсоздается поле и barему присваивается значение параметра. Геттер не создается.

private val bar: Int

Такое объявление параметра создаст private val barполе с частным геттером. Это поведение такое же, как и выше, независимо от того, использовался ли параметр рядом с конструктором (например, in toString()или нет).

val bar: Int

То же, что и выше, но Scala-подобный геттер является общедоступным

bar: Int в случае классов

Когда используются классы case, по умолчанию каждый параметр имеет valмодификатор.

Томаш Нуркевич
источник
15
В случае классов все параметры станут «общедоступными» val.
drexin 04
7
Гоша, время от времени я ношу очки, но это уже слишком.
om-nom-nom
1
@ om-nom-nom: извини, я не понимаю. Следует ли улучшить форматирование / структуру, чтобы сделать ее более читаемой?
Tomasz Nurkiewicz
1
@TomaszNurkiewicz: varдоступен и имеет смысл для рендеринга параметров конструктора в (изменяемые) свойства класса как в не-, так caseи в caseклассах.
Randall Schulz
8
В книге «Scala для нетерпеливых» написано, что bar: Intскомпилировано вprivate[this] val bar: Int
MyTitle
98

В первом случае barэто только параметр конструктора. Поскольку главный конструктор является содержимым самого класса, он доступен в нем, но только из этого самого экземпляра. Так что это почти эквивалентно:

class Foo(private[this] val bar:Int)

С другой стороны, во втором случае barэто обычное частное поле, поэтому оно доступно для этого экземпляра и других экземпляров Foo. Например, это нормально компилируется:

class Foo(private val bar: Int) {
  def otherBar(f: Foo) {
    println(f.bar) // access bar of another foo
  }
}

И работает:

scala> val a = new Foo(1)
a: Foo = Foo@7a99d0af

scala> a.otherBar(new Foo(3))
3

Но это не так:

class Foo(bar: Int) {
  def otherBar(f: Foo) {
    println(f.bar) // error! cannot access bar of another foo
  }
}
gourlaysama
источник
9
это лучший ответ, чем принятый; он подчеркивает разницу между голым bar: Intи private val ....
hraban