HOWTO · Scala

Scala で変数の型を見つける

この記事では、Scala で変数の型を見つける方法について説明します。

このページの内容

Scala には、あらゆる型の疑問に答える単一の typeof 操作はありません。変数の宣言型や推論型はコンパイル時に決まる性質です。実行時には、オブジェクトのクラスを調べる、既知の型ごとに処理を分ける、値が指定した型に当てはまるか確認する、またはジェネリック型のメタデータを要求するといった方法があります。コードが必要とする情報に応じて選びましょう。

実行時の型を何として知りたいかを選ぶ

プログラムで扱うケースが決まっている場合は、パターンマッチングを使います。オブジェクトの実行時クラスを調べるには getClass を使い、短い表示名が必要なら getSimpleName を使います。指定した型に当てはまるかを真偽値で確認するには isInstanceOf を使います。ジェネリック型の情報には Manifest と TypeTag もありますが、これらはメタデータを扱う仕組みであり、ほかの操作をあらゆる場面で置き換えるものではありません。

既知の型にはパターンマッチングを使う

パターンマッチングは、値を自分で記述したケースと照合します。次の単独で実行できる例では、よく使われる値にラベルを付け、それ以外の値にはフォールバックを返します。スクリプト実行時のホスト名検索を避けるため、起動コマンドでは Scala のコンパイルデーモンを無効にしています。

scala -nocompdaemon -e '
def label(value: Any): String = value match {
  case _: String => "String"
  case _: Int => "Int"
  case _: Double => "Double"
  case _ => "Other"
}

List[Any]("hello", 42, 3.14).foreach(value => println(label(value)))
'
String
Int
Double

既知のケースごとに異なる処理が必要な場合、この方法が役立ちます。ただし、可能な型をすべて自動的に検出するわけではありません。独自の sealed な階層では、具体的なケースクラスを照合し、この例のケース以外にも階層や入力が広がる可能性がある場合はフォールバックも含めてください。

getClass でオブジェクトの実行時クラスを調べる

value.getClass を呼び出すと、オブジェクトの実行時 Class を取得できます。たとえば val runtimeClass = value.getClass とすれば、そのクラスを調べたり、別のクラスと比較したりできます。これはオブジェクトの実行時クラスを示すもので、変数の宣言型を報告するものではなく、ジェネリック型引数を完全に示すものでもありません。

短い表示用ラベルが必要な場合は、value.getClass.getSimpleName を使います。この文字列は表示用として扱いましょう。クラス名は実装によって変わることがあり、単純名は安定した型チェック用 API ではありません。組み込みオブジェクトと同じ方法で、独自クラスのインスタンスも調べられます。

Manifest と TypeTag でジェネリック型の情報を得る

ジェネリック型パラメーターは、実行時にオブジェクトから常に取得できるとは限りません。Scala の Manifest と TypeTag は、型について利用可能なメタデータと使用中の Scala 環境に応じて、ジェネリックコードから要求できる型メタデータを提供します。たとえば Scala のコードでは、(implicit m: Manifest[T]) のようなメソッドパラメーターを宣言したり、TypeTag[T] のコンテキスト境界を使ったりして、T に提供されたメタデータを調べられます。

ジェネリックメソッドで型パラメーターの情報が必要な場合、これらの仕組みが役立つことがあります。ただし、あらゆる値について完全な情報が得られるとは限りません。また、文字列表現を安定したシリアライズ形式として扱わないでください。目的が既知のいくつかのケースに分岐することや、単一の型を確認することだけなら、パターンマッチングや isInstanceOf のほうが直接的です。

isInstanceOf で値を確認する

必要な結果が単純な true または false なら、value.isInstanceOf[SomeType] を使います。String のような型だけでなく、指定した独自型にも使えます。この式が答えるのは、値がその型チェックに当てはまるかどうかです。型の説明を返したり、コレクションの要素型を明らかにしたりするものではありません。

型ごとに処理を分ける必要がある場合は、チェックと処理を一つの式にまとめられるパターンマッチングを優先しましょう。実行時に利用できないジェネリック型引数を型チェックから推測しようとしないでください。

用途に合った方法を選ぶ

  • 既知の選択肢を処理するには、フォールバックを用意したパターンマッチングを使います。
  • オブジェクトの実行時クラスを調べたり表示したりするには getClass を使います。短いラベルが必要な場合に限り getSimpleName を使います。
  • 指定した型に当てはまるかをはい・いいえで確認するには isInstanceOf を使います。
  • ジェネリックコードで型メタデータを要求するには Manifest または TypeTag を検討し、使用中の Scala 環境で利用できるメタデータを考慮します。

これらはいずれも万能な typeof ではありません。宣言型はコンパイル時の型チェックに関するものであり、実行時の操作が示すのは、それぞれが提供するクラス、チェック結果、またはメタデータに限られます。