実行時に変数の型を取得したい。どうすればいいですか?
したがって、厳密に言えば、「変数の型」は常に存在し、型パラメーターとして渡すことができます。例えば:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
しかし、あなたが何をしたいのかによってはdo、それはあなたを助けませんたとえば、変数の型が何であるかを知りたくないが、valueの型が次のような特定の型であるかどうかを知りたい場合があります。この:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
ここでは、変数Any
のタイプは重要ではありません。重要なのは、チェックされるのは、値5
のタイプです。実際、T
は役に立たない-代わりにdef f(v: Any)
と書いたかもしれない。また、これはClassTag
または以下で説明する値のClass
のいずれかを使用し、型の型パラメーターを確認できません:何かがList[_]
(何かのList
)かどうかは確認できますが、たとえばList[Int]
またはList[String]
。
別の可能性は、変数の型をreifyしたいということです。つまり、型を値に変換したいので、格納したり、渡したりすることができます。これにはリフレクションが含まれ、ClassTag
またはTypeTag
のいずれかを使用します。例えば:
val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"
ClassTag
を使用すると、match
で受け取った型パラメーターも使用できます。これは機能しません:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
しかし、これは:
val x = 'c'
val y = 5
val z: Any = 5
import scala.reflect.ClassTag
def f[A, B: ClassTag](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
f(x, y) // A (Char) is not a B (Int)
f(x, z) // A (Char) is a B (Any)
ここでは、context bounds構文B : ClassTag
を使用しています。これは、前のClassTag
の例の暗黙パラメーターと同様に機能しますが、匿名変数を使用します。
次のように、値のClassTag
からClass
を取得することもできます。
val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f(a: Any, b: Any) = {
val B = ClassTag(b.getClass)
ClassTag(a.getClass) match {
case B => "a is the same class as b"
case _ => "a is not the same class as b"
}
}
f(x, y) == f(y, x) // true, a is the same class as b
ClassTag
は、基本クラスのみを対象とし、型パラメーターは対象としないという点で制限されます。つまり、List[Int]
とList[String]
のClassTag
は同じList
です。型パラメーターが必要な場合は、代わりにTypeTag
を使用する必要があります。ただし、JVMのerasureにより、TypeTag
は値から取得できず、パターンマッチで使用することもできません。
TypeTag
を使用した例は非常に複雑になる可能性があります。2つのタイプタグを比較することさえ、以下に示すように正確ではありません。
import scala.reflect.runtime.universe.TypeTag
def f[A, B](a: A, b: B)(implicit evA: TypeTag[A], evB: TypeTag[B]) = evA == evB
type X = Int
val x: X = 5
val y = 5
f(x, y) // false, X is not the same type as Int
もちろん、その比較をtrueに戻す方法はありますが、実際にTypeTag
をカバーするには本の章がいくつか必要になるので、ここで停止します。
最後に、変数の型はまったく気にしないかもしれません。値のクラスとは何かを知りたいだけかもしれません。その場合、答えはかなり単純です。
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
ただし、達成したいことをより具体的にして、答えがより重要になるようにした方が良いでしょう。
質問は不完全だと思います。何らかのタイプクラスのタイプ情報を取得したい場合は、以下をご覧ください。
指定したとおりに印刷する場合:
scala> def manOf[T: Manifest](t: T): Manifest[T] = manifest[T]
manOf: [T](t: T)(implicit evidence$1: Manifest[T])Manifest[T]
scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)
scala> println(manOf(x))
scala.collection.immutable.List[Int]
Replモードの場合
scala> :type List(1,2,3)
List[Int]
または、クラスのタイプを知りたいだけの場合は、@ monkjackが"string".getClass
が説明するように目的を解決するかもしれません
変数のタイプで、変数が指すオブジェクトの実行時クラスを意味する場合、すべてのオブジェクトが持つクラス参照を通じて取得できます。
val name = "sam";
name: Java.lang.String = sam
name.getClass
res0: Java.lang.Class[_] = class Java.lang.String
ただし、変数が宣言された型を意味する場合、それを取得することはできません。例えば、あなたが言うなら
val name: Object = "sam"
上記のコードからString
が返されます。
私はそれをテストしましたが、うまくいきました
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}