Czy parametry konstruktora scala mają domyślnie wartość prywatną?

130

Próbowałem:

class Foo(bar: Int)

vs:

class Foo(private val bar: Int)

i wydaje się, że zachowują się tak samo, chociaż nie mogłem znaleźć nigdzie stwierdzenia, które (bar: Int)rozszerza się do, (private val bar: Int)więc moje pytanie brzmi: czy są one identyczne / podobne?

Na marginesie, próbowałem użyć -Xprint:typertych fragmentów kodu i generują ten sam kod, z wyjątkiem dodatkowej linii w drugim. Jak mam przeczytać tę dodatkową linijkę?

..
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>();
    ()
  }
}
..
Żaden
źródło

Odpowiedzi:

181

bar: Int

To zaledwie parametr konstruktora. Jeśli ta zmienna nie jest używana nigdzie poza konstruktorem, pozostaje tam. Żadne pole nie jest generowane. W przeciwnym razie private val barpole jest tworzone i barprzypisywana jest do niego wartość parametru. Nie jest tworzony żaden getter.

private val bar: Int

Taka deklaracja parametru utworzy private val barpole z prywatnym geterem. To zachowanie jest takie samo jak powyżej, niezależnie od tego, czy parametr został użyty obok konstruktora (np. In toString()czy nie).

val bar: Int

To samo co powyżej, ale getter podobny do Scali jest publiczny

bar: Int w klasach przypadków

W przypadku klas przypadków domyślnie każdy parametr ma valmodyfikator.

Tomasz Nurkiewicz
źródło
15
W przypadku klas wszystkie parametry staną się „publiczne” val.
drexin
7
O rany, od czasu do czasu noszę okulary, ale to za dużo.
om-nom-nom
1
@ om-nom-nom: przepraszam, nie rozumiem. Czy powinienem poprawić formatowanie / strukturę, aby była bardziej czytelna?
Tomasz Nurkiewicz
1
@TomaszNurkiewicz: varjest dostępny i sensowny do renderowania parametrów konstruktora na (zmienne) właściwości klas zarówno w klasach nie-, jak casei caseklasach.
Randall Schulz,
8
W książce „Scala for the Impatient” napisanej bar: Intdoprivate[this] val bar: Int
MyTitle
99

W pierwszym przypadku barjest tylko parametrem konstruktora. Ponieważ głównym konstruktorem jest zawartość samej klasy, jest ona dostępna w niej, ale tylko z tej samej instancji. Więc jest to prawie równoważne z:

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

Z drugiej strony w drugim przypadku barjest to normalne pole prywatne, więc jest dostępne dla tej instancji i innych instancji Foo. Na przykład kompiluje się dobrze:

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

I biegnie:

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

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

Ale to nie jest:

class Foo(bar: Int) {
  def otherBar(f: Foo) {
    println(f.bar) // error! cannot access bar of another foo
  }
}
gourlaysama
źródło
9
to jest lepsza odpowiedź niż przyjęta; podkreśla różnicę między gołymi bar: Inti private val ....
hraban