今回から第二部に突入です!
Scalaを勉強していて気づいたのですが、型、型、かた、カタ、カタカタ・・・
__型__という言葉が登場する頻度が高いんです!
もしかして型が重要な要素の一つかも・・・
なので型について語ってみます!
#型とは
型とは何か?型とつくモノを洗い出してみました。
- ノート型パソコン
- 血液型
- ネコ型ロボット
色々ありますね。もっとありますが、便宜上これだけです。
最も身近な__ネコ型ロボット__で考えてみます。
ネコ型ロボットと言えば、そう!あの「ドラえもん」ですね!
__ネコ型ロボット__を__抽象__と考えると、「ドラえもん」は
ネコ型ロボットの__具象__だと気づいちゃいました!
と、ということは、他のモノでもこの関係性が見出せるのか?
抽象 | 具象 |
---|---|
ノート型パソコン | MBP、Let's Note, ThinkPad |
血液型 | A型、B型、AB型、O型 |
ネコ型ロボット | ドラえもん、ドラミちゃん |
いきなり話がぶっ飛んでいますが、
これって 型=抽象 と考えることが可能ですよね。
データ型
プログラミングの世界での型、データ型で考えると
抽象 | 具象 |
---|---|
データ型 | 数値型, 浮動小数点型, 文字列型 |
となります。
でもこの具象はまだ具体的になりきっていません。
例えば、整数型の具象は1
や2
ですよね。
なので、「数値型, 浮動小数点型, 文字列型」を抽象として
具象を挙げてみたのが、以下となります。
抽象 | 具象 |
---|---|
数値型 | 1, 2, 3 |
浮動小数点型 | 1.5, 2.2, 3.14 |
文字列型 | 雷電, 飛燕, 月光 |
このテーブルを見ていると、具象を別の言葉、__値__に置き換えることができますね。
型を見てみる
先ほどのデータ型のテーブルの一部を、コマンドラインで使える
REPL(read-eval-print loop)で見てみましょう。
まずはコマンドプロンプトまたはターミナルを開き、scalaと打ってみます。
$ scala
Welcome to Scala version 2.10.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala>
次にval i = 1
、val d = 1.5
、val s = "雷電"
と入力してみましょう。結果は以下となります。
scala> val i = 1
i: Int = 1
scala> val d = 1.5
d: Double = 1.5
scala> val s = "雷電"
s: String = "雷電"
型の話をしているのですが、実は入力には型宣言がありません。
代わりに出力されていることに気づいたでしょうか?
Int
、Double
、String
ですね。
型を解決してくれるのがScalaの素晴らしいところです。
型宣言しなくても型を解決してくれるのが
Scalaの持つ強力な機能の1つ、__型推論__です。
#オブジェクト指向と型
型を抽象と捉えると、ある言葉が頭に浮かんできます。
__オブジェクト指向__ですね。
##型としてのクラス
オブジェクト指向の世界だと、型はやっぱり__クラス__です。
クラスを__抽象__とすると、インスタンスが__具象__になります。
オブジェクトは両方を包含するモノです。
実際に抽象と具象を、__車__を対象として試してみます。
object Car {
def main(args: Array[String]){
var car = new Car("blue")
car.run
}
private def output(message: String):Unit=println(message)
}
class Car(color: String) {
def run = {
Car.output("Start!!!")
}
}
動かすには、scalac
でコンパイルした後、scala
で実行します。
$ scalac Car.scala
$ scala Car
Start!!!
ソースの中身は下記のようになっています。
-
object
のmain
メソッドで、Carクラスをインスタンス化 -
class
でフィールドcolor
とメソッドrun
を持つクラスCarを__型宣言__
クラスを型として使う場合も、変数定義で__型の明示がいりません。__
同様なソースをJavaで表すとこうなります。
main
メソッドをCarクラス内に入れているのは許してください。
public class Car {
public static void main(String[] args) {
final Car car = new Car("blue");
car.run();
}
private static void output(String message) {
System.out.println(message);
}
private final String color;
public Car(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void run() {
output("Start!!!");
}
}
Javaだと変数car
の型を明示する必要がありましたね。
#コンパニオンオブジェクト
ソースCar.scalaはちょっと奇妙に見えませんか?
シングルトンオブジェクトを表すobject
キーワードでCarを宣言しているのに
class
でもCarを宣言している。
ここには
- コンパニオンオブジェクト
- コンパニオンクラス
というモノが存在しています。
コンパニオンオブジェクト
同じソースファイル内に存在する、クラスと同じ名前のシングルトンオブジェクトのことです。
object Car {...}
の方となります。
コンパニオンクラス
同じソースファイル内に存在する、シングルトンオブジェクトと同じ名前のクラスのことです。
class Car {...}
の方となります。
コンパニオンオブジェクトの例
コンパニオンオブジェクトとコンパニオンクラスは、互いに非公開のメンバーに
アクセスすることができます。
run
メソッドの内部がコンパニオンクラスからコンパニオンオブジェクトの
メンバーを呼び出している例となります。
def run = {
Car.output("Start!!!")
}
今回はここまでにしておきますが、他の回でもコンパニオンオブジェクトに触れたいと思います。
継承による型
型の話となるとやはり、Javaでいうインタフェースが気になるものです。
Java界では、インタフェースを制するものはJavaを制する、
とまで言われているとか言われていないとか。
Scalaにはinterface
がありません。代わりに、__クラスの継承__と__トレイト__があります。
今回はクラスの継承を試してみます。
object CarExtends {
def main(args: Array[String]){
var car = new Car("blue")
output(car)
car.run
var truck = new Truck("Silver")
output(truck)
truck.run
}
def output(car: Car):Unit=println("Color is " + car.color + ".")
}
class Car(val color: String) {
def run = println("Start!!!")
}
class Truck(color: String) extends Car(color) {
override def run =println("Truck start!!!")
}
実行してみます。
$ scalac CarExtends.scala
$ scala CarExtends
Color is blue.
Start!!!
Color is Silver.
Truck start!!!
インタフェースとして型を活用している箇所がわかりますか?
def output(car: Car):Unit=println("Color is " + car.color + ".")
このoutput
メソッドです。
Carクラスのインスタンスを引数に取り、フィールドcolor
を出力します。
output
メソッドを使用している箇所は2箇所あります。
var car = new Car("blue")
output(car)
ここでは、Carクラスのインスタンスを直接生成しています。
var truck = new Truck("Silver")
output(truck)
こちらでは、Carクラスを継承しているTruckクラスのインスタンスを生成しています。
Truck
クラスはCar
クラスを継承しているため、output
メソッドの引数に使えるのです。
適切な型を定義していけば、__多態性__も簡易に実現できそうな予感がしています。
#まとめ
型について語ってみましたが、ほんの一部分しか語れていません。
型を、抽象・具象というオブジェクト指向の考え方を取り入れて記述してみましたが
いかがだったでしょうか?
Scalaで登場する型について、今後も語っていきます。
型__を__体で感じてくれたかな?