newをサボる方法

ソースコード読んでたらちょっとしたテクニックを見つけました。何かちょっと嬉しい!
なのでメモしておきます。

「new」をサボってるクラスがあるぞ

普通のクラスは「new」キーワードでインスタンス化します。

var nanika = new Nanika

けれども、よく考えてみるとListとかMapとかを作るときに「new」なんてつけてませんでした。

var list = List(1,2,3)

これはなんかずるい。不公平だ。格差だ。
こんな不公平がまかり通っていては若者が夢を失ってしまいIT業界の未来に絶望して六本木ヒルズが爆発してしまうかもしれません。
若者の未来のために英語のコメントばかりで気が狂いそうなソースコードの中身を調べてみました。
List.scala

結果

こんな感じで実現できました。

  1. クラスを宣言する
  2. クラスと同じ名前でオブジェクトを宣言する
  3. オブジェクトは関数クラスを継承しておく
  4. オブジェクトのapplyメソッドでクラスをnewしたものを返す
class Nanika
object Nanika extends (()=>Nanika) {
  def apply = new Nanika
}

クラスと同じ名前のオブジェクトを関数として宣言して、その関数をファクトリ・メソッドみたいなものにしてしまうわけですね。
今気づいたのですが、このやり方だとインスタンスを作るときに「new」は省略できるけどカッコが省略できません。

○ var n = Nanika()
× var n = Nanika

下の書き方だと関数を継承した方のNanikaオブジェクトが代入されてしまいます。そりゃあそうか。
なかなか上手くいかないものです。


コンストラクタに引数を渡したいときはこんな感じ。

class Nanika(id: Int, name: String) {
  val _id = id;
  val _name = name;
}
object Nanika extends ((Int, String)=>Nanika) {
  def apply(id:Int, name:String) = new Nanika(id, name)
}

「new」を書くのがイヤでイヤでしょうがない人は試してみてください。