menu
書いてる野郎
orebike@gmail.com
Scala のクラスは Java のように1ファイル1クラスではないし、ファイル名とクラス名を一致させる必要もない。 好きに作れる。ディレクトリ構成に関しては パッケージ構成 で
var でフィールドを定義して、def でメソッドを定義する。簡単である。
class Hoge { var piyo:Int = 123 def fuga(a:Int):Int = { piyo + a } }
フィールドへのアクセスはフィールド名そのままでできる
var hoge: Hoge = new Hoge() hoge.piyo = 234 println(hoge.piyo)
しかし実際は暗黙的にメソッドが呼び出されている。 フィールドを作ると同時に
def piyo = { piyo } def piyo_=(v:Int) = { piyo = v }
が自動的に定義されてこれが呼び出される。この2つのメソッドは特殊なメソッドで通常のメソッドとは違う呼び出し方ができるというものである。
メソッドは何もつけなければ基本的にスコープは Java で言う public に設定される。
内部からのアクセスは Java 同様に普通に書けばよい。this で明示することもできる。
class Hoge { var piyo = 1 def fuga = { piyo = 2 piyo = 3 this.piyo } }
Scala にコンストラクタは無く、クラスのむき出しになった部分がそのまま実行される。
class Hoge { println("Go!") var piyo:Int = 123 def fuga(a:Int):Int = { piyo + a } println("End!") }
このへんの機構は JavaScript そっくりである。
つまりパラメータが必要ならばこうすればよい
class Hoge(name:String) { println(name) println("Go!") var piyo:Int = 123 def fuga(a:Int):Int = { piyo + a } println("End!") }
コンストラクタを沢山作る
class Hoge(name:String) { println(name) println("Go!") def this() = { this("aaaa") } var piyo:Int = 123 def fuga(a:Int):Int = { piyo + a } println("End!") }
このように this キーワードを使う。コンストラクタの中では別のコンストラクタを必ず呼ばないといけない。 つまり最外のオリジナルのコンストラクタは必ず呼ばれるということになる。
クラスの操作として実装される関数がメソッドである。
インスタンスからなんらかの値を単純に返す場合は
class Hoge { def piyo = { 123 } }
このように単純にメソッド名に処理を入れ込む形で書く
引数は無いがそれを実行することでインスタンスの内部状態が変わったりする副作用を伴う場合は
class Hoge { var fuga:Int = 123 def piyo() = { this.fuga = 345 } }
このように括弧付きで宣言する。括弧付きで宣言しておかないと。Scala では括弧付きで呼び出せないのだ。
コーディング規約として副作用を伴うメソッドは括弧付きで呼び出すのが作法(なしでも呼び出せる)なのでこのようにする。
つまり、同名メソッドの引数の数とか型違い。Scala でもできる。
Scala では何も付けなければ自動的に public でどこからでもアクセス可能になる
Java の protected は糞仕様で、パッケージからは public になってしまうという謎な挙動だったが、 Scala は、サブクラスからのみOKになるという極めて普通な挙動になる。
親クラスのコンストラクタを使う場合
class Hoge(aaa:Int) { } class Piyo(aaa:Int) extends Hoge(aaa) { }
このように、自身のコンストラクタへのパラメータを継承元に横流しするという、記述をする。 これは、継承する時に(複数あるであろう)親のコンストラクタを1個選ばないといけないということ?
これは JavaScript の apply を利用した this 取り替えの継承と形式となんとなく似ている
abstract キーワードを使うと抽象クラスを作成できる。そこで宣言だけで初期化を省略するとそれぞれ抽象フィールド、抽象メソッドとなってサブクラスでの実装を強制できる。
abstract class Hoge { val piyo:Int def fuga():Int }
当然抽象クラスなので new
できない
一般的にバリューオブジェクトと呼ばれるメソッドは無く単に値を入れるだけの目的でクラスを作ることがよくある
この場合 Scala では非常に簡素に書くことができるようになっている。
case class HogeHoge(name:String, age,Int)
これだけで完了である。 1行で済むのでワザワザファイルを作ってクラスを別個に定義しなくても使う場所の真横で作れる手軽さである。
クラスで apply という名前を持つメソッドはメソッド名を省略して、括弧だけで呼び出せるようになる
class Hoge { var v1:Int = 10 var v2:Int = 20 var v3:Int = 30 def apply(v:Int) { v match { case 1 => this.v1 case 2 => this.v2 case 3 => this.v3 } } }
と作ると、このように呼び出せる
var hoge:Hoge = new Hoge() println(hoge(2)) // => 20
クラス自体が配列や連想配列のような入れ物を表現する場合に、この記法を使うとまるでそういう文法があって直接的に内部にアクセスしているように書けるのでよく使われる
class Hoge { var v1:Int = 10 var v2:Int = 20 var v3:Int = 30 def update(k:Int, v:Int) { k match { case 1 => this.v1 = v case 2 => this.v2 = v case 3 => this.v3 = v } } }
と作ると、このように呼び出せる
var hoge:Hoge = new Hoge() hoge(2) = 40
クラス自体が連想配列的な機能を持つ場合、update という名前のメソッドを、あたかもキー指定で代入しているように使えるという記法である。
非常に紛らわしいが
var hoge:Hoge = new Hoge() hoge.update(2, 40) hoge(2) = 40
この2つは同じ