SSブログ

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


nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。