回答:
したがって、厳密に言えば、「変数の型」は常に存在し、型パラメーターとして渡すことができます。例えば:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
しかしによっては、あなたがしたいものをやる、それはあなたを助けにはなりません。たとえば、変数のタイプが何であるかを知りたくないが、値のタイプが次のような特定のタイプであるかどうかを知りたい場合があります。
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]
。
もう1つの可能性は、変数の型を具体化することです。つまり、型を値に変換して、それを格納したり、渡し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"
Aでは、で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)
ここでは、コンテキスト境界構文を使用しています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
A ClassTag
は、基本クラスのみをカバーし、型パラメーターはカバーしないという点で制限されています。つまりClassTag
、List[Int]
とList[String]
は同じですList
。型パラメーターが必要な場合は、TypeTag
代わりにを使用する必要があります。A TypeTag
ただし、値から得ることができず、またそれは、パターンマッチに使用することができ、JVMのが原因消去。
の例は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
ただし、答えをより的確にとらえることができるように、達成したいことをより具体的にした方がよいでしょう。
Int
ですがAny
、そうでAny
はありませんInt
。Scala 2.10で動作し、Scala 2.11で動作するはずですが、なぜそうでないのかわかりません。
a match { case _: B => ...
は変数a
の型ではなく、変数の実際の値の型をテストしますa
。あなたはscala 2.10.6で言うことを返すという点で正しいです。しかし、それはバグであるはずです。Scala 2.11.8では、実際の値の型がテストされます。
質問は不完全だと思います。タイプクラスのタイプ情報を取得したい場合は、以下をご覧ください。
指定したとおりに印刷する場合:
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
、目的を解決する可能性があります
typeof x
と同様に、ここでmanOf(x)
はデータ型と言います。
変数のタイプによる場合オブジェクトの実行時のクラスを意味する変数のポイントは、あなたはすべてのオブジェクトが持っているクラス参照を介してこれを得ることができること。
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
ただし、変数が宣言された型を意味する場合は、それを取得できません。たとえば、あなたが言うなら
val name: Object = "sam"
それでもString
、上記のコードからは戻ってきます。
name.getClass.getSimpleName
さらに読みやすい出力を行うこともできます
私はそれをテストしました、そしてそれはうまくいきました
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5
がのインスタンスInt
とのインスタンスの両方だからAny
です。それとは別に、あなたの説明は完璧でした:)