1. ホーム
  2. scala

[解決済み] 実行時に変数の型を取得したい

2022-02-10 02:19:27

質問

実行時に変数の型を取得したいのですが、どうすればよいですか? どうすればよいですか?

どのように解決するのですか?

つまり、厳密に言えば、"変数の型"は常に存在し、型パラメータとして渡すことができるのです。例えば

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] .

もう一つの可能性は リファイ という変数があります。つまり、型を値に変換して、それを保存したり、渡したりすることができるようにしたいのです。これにはリフレクションが含まれ、次のいずれかを使用します。 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

もちろん、この比較が真を返すようにする方法はありますが、実際にカバーするには本の数章が必要です。 TypeTag ということで、この辺でやめておきます。

最後に、変数の型はまったく気にしないという人もいるかもしれません。その場合、答えはとてもシンプルです。

val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it

しかし、何を実現したいのか、もっと具体的に書いた方が、よりポイントを押さえた回答ができるはずです。