Deletions are marked like this. | Additions are marked like this. |
Line 100: | Line 100: |
ScalaではJavaのやり方とはまったく異なる。Javaでは上のように、「呼び出しサイト」で定義されるが、Scalaでは「宣言サイト」で定義される(これらの言葉は「プログラミングScalaから拝借)。 |
ScalaではJavaのやり方とはまったく異なる。Javaでは上のように、「呼び出しサイト」で定義するが、Scalaでは「宣言サイト」で定義する(これらの言葉は「プログラミングScalaから拝借)。 以下はだめだが、 {{{ class Animal class Fish extends Animal; class Zoo[T <: Animal] { } val fishZoo = new Zoo[Fish]; val animalZoo: Zoo[Animal] = fishZoo; }}} 以下はOK {{{ class Animal class Fish extends Animal; class Zoo[+T <: Animal] { // Tの前に+をつけただけ } val fishZoo = new Zoo[Fish]; val animalZoo: Zoo[Animal] = fishZoo; }}} |
Scalaの型システム
単純な型パラメータ
Javaでは以下のように書ける。
class Animal { } class Fish extends Animal { } class Zoo<T> { public void add(T animal) { } } ... Zoo<Animal>zoo = new Zoo<Animal>(); zoo.add(new Fish()); ...
これと等価な(たぶん)Scalaコードは以下。
class Animal class Fish extends Animal; class Zoo[T] { def add(a:T) { } } val zoo = new Zoo[Animal]; zoo add new Fish
上限型境界
上のコードのままだと、Animal以外のZooの作成が可能になってしまう。
Zoo<Integer>zooInt = new Zoo<Integer>(); // 可能だが意味不明
また、そもそもこのままではZooクラスの中でAnimalのメソッドを呼び出せない。Tはどんな型でも可能だからである。 Zooの中でAnimalのメソッドを(キャスト無しに)呼び出すためには、TがAnimalクラスあるいはそのサブクラスであることを明示する必要がある。
そこで上限型境界指定を行う。Javaでは以下のようなものだった
class Zoo<T extends Animal> { ... } Zoo<Fish>fishZoo = new Zoo<Fish>(); // OK Zoo<Integer>intZoo = new Zoo<Integer>(); // エラー
Scalaでは以下になる
class Zoo[T <: Animal] { ... } .... val fishZoo = new Zoo[Fish]; // OK val intZoo = new Zoo[Int]; // エラー
下限型境界
上限型境界と同様に、下限型境界というものもある。Scalaでは
class Zoo[T >: Animal] {
などと記述するが、Javaにはこの機能がない。つまり、
class Zoo<T super Animal> {
と書くことはできない。後述する変位指定ではJavaも
<? super Animal>
などと書けるのだが(だったかな?)、下限型境界指定は存在しない。
しかし、そもそも下限型境界の使いどころが不明なのでこれについては省略。
変位指定の書き方
「変位」とは何か、JavaとScalaのその違いは何かはおいておき、ここではその書き方のみに注目してみる。
Javaの変位指定
Javaでは「その型を使う時に」「? extends Animal」などと記述して変位を指定する。 たとえば、
class Animal { } class Fish extends Animal { } class Zoo<T extends Animal> { ... } ... Zoo<Fish>fishZoo = new Zoo<Fish>(); Zoo<Animal>animalZoo1 = fishZoo; // エラー Zoo<? extends Animal>animalZoo2 = fishZoo; // ※OK ...
上の例でfishZooはanimalZoo1に代入することはできない(コンパイルエラー)。animalZoo2では、<? extends Animal>として変位を指定している。
Scalaの変位指定
ScalaではJavaのやり方とはまったく異なる。Javaでは上のように、「呼び出しサイト」で定義するが、Scalaでは「宣言サイト」で定義する(これらの言葉は「プログラミングScalaから拝借)。
以下はだめだが、
class Animal class Fish extends Animal; class Zoo[T <: Animal] { } val fishZoo = new Zoo[Fish]; val animalZoo: Zoo[Animal] = fishZoo;
以下はOK
class Animal class Fish extends Animal; class Zoo[+T <: Animal] { // Tの前に+をつけただけ } val fishZoo = new Zoo[Fish]; val animalZoo: Zoo[Animal] = fishZoo;