Scala のコンストラクタ [Scala]
「[Scala][Java] クラスとデフォルトコンストラクタ」 [1] より引用。
とかすると,勝手にメンバをつくり値を代入してくれる. で,じゃぁメンバのアクセス権限はどうかなと思って,class Dimension(width: int, height: int) { override def toString: String = "[" + width + "," + height + "]" } val size = new Dimension(320, 240) println(size)
を実行すると,println(size.width) println(size.height)
error: value width is not a member of Dimension println(size.width) ^ error: value height is not a member of Dimension println(size.height) ^ two errors foundということで隠蔽されている.
殆ど重箱の隅のような話になってしまうけど、これは自動でメンバを作って代入してアクセス制限をかけているのではなくて、「クラスのプライマリコンストラクタの仮引数のスコープはクラス定義全体であり、したがってクラス定義内のメソッドからのみ可視である」という解釈を私は今までしていて、たぶんそちらのほうが正しいと思う。
以下のような例を作ると「メンバでない」と「メンバだがアクセス可能でない」の差がエラーメッセージに現れる。
scala> class A(m: Int) defined class A scala> class B(n: Int) { private val m = n } defined class B scala> (new A(123)).m <console>:5: error: value m is not a member of A val res0 = (new A(123)).m ^ scala> (new B(123)).m <console>:5: error: value m cannot be accessed in B val res1 = (new B(123)).m ^
逆に私は Scala でクラスのコンストラクタが多重定義できることの方を知らなかった(あまり Scala の文献に現れないし…)。同名オブジェクトの apply メソッドを多重定義するみたいなことをしなければいけないのだと今まで思っていました。
追記: 書いた後で思ったけど、じゃあ case class はどうなっているんだろう。
追記:
仕様書を読んでみるといろいろと(私にとっての)新しい知識が得られた。以下のように仮引数に val とか var とかを付けた場合は本当にメンバである(自動でアクセサを定義してくれる)。
scala> class A(val m: Int) defined class A scala> (new A(123)).m res0: Int = 123 scala> class B(var m:Int) defined class B scala> val b = new B(123) b: B = B@17366cb scala> b.m res1: Int = 123 scala> b.m = 456 scala> b.m res3: Int = 456
そして case class の場合はこの val が暗黙のうちに付与されたものとみなされる。
[1] http://cappuccino.jp/keisuken/logbook/20070817.html#p04
コメント 0