Help us understand the problem. What is going on with this article?

第5章:Scalaの型について語る

More than 5 years have passed since last update.

今回から第二部に突入です!

Scalaを勉強していて気づいたのですが、型、型、かた、カタ、カタカタ・・・
という言葉が登場する頻度が高いんです!
もしかして型が重要な要素の一つかも・・・

なので型について語ってみます!

型とは

型とは何か?型とつくモノを洗い出してみました。

  • ノート型パソコン
  • 血液型
  • ネコ型ロボット

色々ありますね。もっとありますが、便宜上これだけです。

最も身近なネコ型ロボットで考えてみます。
ネコ型ロボットと言えば、そう!あの「ドラえもん」ですね!
ネコ型ロボット抽象と考えると、「ドラえもん」は
ネコ型ロボットの具象だと気づいちゃいました!

と、ということは、他のモノでもこの関係性が見出せるのか?

抽象 具象
ノート型パソコン MBP、Let's Note, ThinkPad
血液型 A型、B型、AB型、O型
ネコ型ロボット ドラえもん、ドラミちゃん

いきなり話がぶっ飛んでいますが、
これって 型=抽象 と考えることが可能ですよね。

データ型

プログラミングの世界での型、データ型で考えると

抽象 具象
データ型 数値型, 浮動小数点型, 文字列型

となります。
でもこの具象はまだ具体的になりきっていません。
例えば、整数型の具象は12ですよね。

なので、「数値型, 浮動小数点型, 文字列型」を抽象として
具象を挙げてみたのが、以下となります。

抽象 具象
数値型 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 = 1val d = 1.5val s = "雷電"
と入力してみましょう。結果は以下となります。

scala> val i = 1
i: Int = 1
scala> val d = 1.5
d: Double = 1.5
scala> val s = "雷電"
s: String = "雷電"

型の話をしているのですが、実は入力には型宣言がありません。
代わりに出力されていることに気づいたでしょうか?

IntDoubleStringですね。
型を解決してくれるのがScalaの素晴らしいところです。

型宣言しなくても型を解決してくれるのが
Scalaの持つ強力な機能の1つ、型推論です。

オブジェクト指向と型

型を抽象と捉えると、ある言葉が頭に浮かんできます。
オブジェクト指向ですね。

型としてのクラス

オブジェクト指向の世界だと、型はやっぱりクラスです。
クラスを抽象とすると、インスタンスが具象になります。
オブジェクトは両方を包含するモノです。

実際に抽象と具象を、を対象として試してみます。

Car.scala
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!!!

ソースの中身は下記のようになっています。

  1. objectmainメソッドで、Carクラスをインスタンス化
  2. classでフィールドcolorとメソッドrunを持つクラスCarを型宣言

クラスを型として使う場合も、変数定義で型の明示がいりません。

同様なソースをJavaで表すとこうなります。
mainメソッドをCarクラス内に入れているのは許してください。

Car.java
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がありません。代わりに、クラスの継承トレイトがあります。
今回はクラスの継承を試してみます。

CarExtends.scala
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で登場する型について、今後も語っていきます。

体で感じてくれたかな?

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away