Scalaではクラスをエイリアスしたいときはtypeというキーワードを利用する。
class Hoge() { def print(): Unit = { println("hoge") } } type Fuga = Hoge val fuga = new Fuga() fuga.print()
しかしこのやり方だけではcase classのエイリアスは出来ない。以下のコードを実行するとエラーが出力される。
case class Hoge() { def print(): Unit = { println("hoge") } } type Fuga = Hoge val fuga = Fuga() fuga.print() // error: not found: value Fuga // val fuga = Fuga() // ^ // one error found
case classの場合、valとtypeの両方を利用してエイリアスしなければならない。以下のコードでうまくいく。
case class Hoge() { def print(): Unit = { println("hoge") } } type Fuga = Hoge val Fuga = Hoge val fuga = Fuga() fuga.print()
仕組み
どうしてこうなっているのかというと、以下の二点が絡んでくる。
object定義はtypeではエイリアス出来ず、valでエイリアス出来る
objectは型ではないので、typeでエイリアス出来ない。(追記: xuweiさんによると、この認識は少し間違っているそうです。正しくはobjectの定義は「型と値を両方同時に定義」するとのことでした。教えて頂いてありがとうございます。)
object Hoge { def print(): Unit = { println("hoge") } } type Fuga = Hoge Fuga.print() // 2015-08-25-091747.scala:5: error: not found: type Hoge // type Fuga = Hoge // ^ // 2015-08-25-091747.scala:6: error: not found: value Fuga // Fuga.print() // ^ // two errors found
そこでvalを使ってobjectをエイリアスする。
object Hoge { def print(): Unit = { println("hoge") } } val Fuga = Hoge Fuga.print()
なぜこれだとうまくいくのか、詳細は分かっていないが、Scalaスケーラブルプログラミングによると
一般に、Scalaは定義のための名前空間を2個しか持っていない (Javaは4個ある)。
- 値 (フ ィ ー ル ド、メ ソ ッ ド、パッケージ、シングルトンオブジェクト)
- 型 (クラス、トレイト)
と書いてあるので、型の名前空間のaliasはtypeで、値の名前空間のエイリアスはvalで出来るのではないかと思った。ただ詳しいことは分かってないので違ってるかもしれない。