런타임에 변수 유형을 얻고 싶습니다.


97

런타임에 변수 유형을 얻고 싶습니다. 어떻게해야합니까?

답변:


132

따라서 엄밀히 말하면 "변수 유형"은 항상 존재하며 유형 매개 변수로 전달 될 수 있습니다. 예를 들면 :

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무언가) 인지 여부를 확인할 수 있지만 예를 들어 a List[Int]또는 인지 여부는 확인할 수 없습니다 List[String].

또 다른 가능성은 당신이 할 것입니다 구체화 변수의 유형입니다. 즉, 당신이 그것을 저장할 수 있도록,이 반사를 포함 등, 주위를 통과, 당신은 사용이 될 것입니다, 값으로 유형을 변환 할입니다 ClassTagTypeTag. 예를 들면 :

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 : ClassTagClassTag

다음 과 같이 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그러나 A 는 JVM 삭제 로 인해 값에서 얻을 수 없으며 패턴 일치에 사용할 수 없습니다 .

예제는 TypeTag매우 복잡해질 수 있습니다. 아래에서 볼 수 있듯이 두 개의 유형 태그를 비교하는 것조차 간단하지 않습니다.

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

그러나 달성하고자하는 것에 대해 더 구체적으로 설명하는 것이 더 낫습니다. 그래야 답이 요점에 더 가깝게 될 수 있습니다.


"But this will :"다음에 작성한 예제 코드는 혼란 스럽습니다. 컴파일되지만 결과는 주석에 표시된 결과가 아닙니다. 두 호출 모두 "A는 B"라는 동일한 결과를 반환합니다. 값 5은의 인스턴스 Int이자의 인스턴스이기 때문 Any입니다. 그 외에도에서, 당신의 설명 : 완벽했다
Readren

@Readren 값은 테스트되지 않고 클래스입니다. Int이다 Any, 그러나 Any아니다 Int. 그것은 Scala 2.10에서 작동하고 Scala 2.11에서 작동 해야하며 왜 그렇지 않은지 모르겠습니다.
Daniel C. Sobral

1
당신과 같은 저명한 사람과 모순되는 것이 두렵지 만 코드 a match { case _: B => ...는 변수 a의 유형이 아닌 변수의 실제 값 유형을 테스트합니다 a. 스칼라 2.10.6에서 말한 내용을 반환한다는 점에서 맞습니다. 하지만 버그 여야합니다. 스칼라 2.11.8에서는 실제 값의 유형이 테스트됩니다.
Readren jul.

내가 찾던 바로 그 ClassTag와 TypeTag의 차이점에 대한 아주 좋은 범위입니다.
marcin_koss

이것을 null 확인하는 방법이 있습니까?
ChiMo

53

질문이 불완전하다고 생각합니다. 어떤 유형 클래스의 유형 정보를 얻으려면 다음과 같이하십시오.

지정한대로 인쇄하려면 다음을 수행하십시오.

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목적을 해결할 수 있습니다.


3
독자 : 이것은 가장 유용한 솔루션 입니다. Javascript에서 typeof x와 같이 여기 manOf(x)에 데이터 유형을 말하십시오!
Peter Krauss

23

에 의해 경우 변수의 유형 당신은 객체의 런타임 클래스를 의미하는 변수 포인트는, 당신은 모든 객체가 가지고있는 클래스 참조를 통해이를 얻을 수 있습니다.

val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String

그러나 변수가 선언 된 유형을 의미하는 경우이를 얻을 수 없습니다. 예를 들면

val name: Object = "sam"

그러면 String위의 코드에서 여전히 다시 얻을 수 있습니다.


8
name.getClass.getSimpleName더 읽기 쉬운 출력을 위해 할 수도 있습니다
David Arenburg

21

나는 그것을 테스트했고 효과가 있었다

val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.