스칼라에서 런타임에 클래스 매개 변수 데이터 유형을 찾는 방법

Nov 29 2020
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._

def getType[T: TypeTag](obj: T) = typeOf[T]

case class Thing(
  val id: Int,
  var name: String
)
val thing = Thing(1, "Apple")

val dataType = getType(thing).decl(TermName("id")).asTerm.typeSignature

dataType match {
 case t if t =:= typeOf[Int] => println("I am Int")
 case t if t =:= typeOf[String] => println("String, Do some stuff")
 case _ => println("Absurd")
}

결과가 Absurd대신 왜인지 이해할 수 없습니다 I am int.

내 목표는 런타임에 클래스 매개 변수의 데이터 유형을 알고 미리 정의 된 유형과 일치시키는 것입니다.

답변

4 DmytroMitin Nov 29 2020 at 17:20

둘 다 현재 dataTypetypeOf[Int]같이 인쇄 Int되지만 showRaw일치하지 않는 이유를 알 수 있습니다.

showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())

문제는 Int반환 Int되는 nullary 메서드 의 유형 과 유형 이 다른 유형이라는 것입니다.

추가하려고 .resultType

val dataType = getType(thing).decl(TermName("id")).asTerm.typeSignature.resultType

dataType match {
  case t if t =:= typeOf[Int] => println("I am Int")
  case t if t =:= typeOf[String] => println("String, Do some stuff")
  case _ => println("Absurd")
} // I am Int

.decl(TermName("id"))getter 기호 를 반환 하는 것도 언급 할 가치가 .decl(TermName("id "))있습니다. 필드 기호를 반환하는 것은 공백이 있습니다. 따라서 또는 기호 이름에 공백을 사용하고.resultType

val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature

나는에 추가 할 것입니다 @TomerShetah 의 대답은 그 목표는 "패턴 일치"와 다음이 (대부분) 컴파일시도 할 수있는 경우 클래스의 모든 필드의 경우 무형가 :

import shapeless.Poly1
import shapeless.syntax.std.product._

object printTypes extends Poly1 {
  implicit val int: Case.Aux[Int, Unit] = at(t => println(s"I am Int: $t")) implicit val string: Case.Aux[String, Unit] = at(t => println(s"String, Do some stuff: $t"))
  implicit def default[V]: Case.Aux[V, Unit] = at(t => println(s"Absurd: $t"))
}
  
thing.toHList.map(printTypes)
// I am Int: 1
// String, Do some stuff: Apple

https://scastie.scala-lang.org/DmytroMitin/N4Idk4KcRumQJZE2CHC0yQ

1 TomerShetah Nov 30 2020 at 11:28

@Dmytrio 답변은 반사가 예상대로 작동하지 않은 이유에 대한 훌륭한 설명입니다.

귀하의 질문에서 귀하가하려는 것은 실제로 케이스 클래스에있는 모든 변수와 패턴 일치한다는 것을 이해할 수 있습니다. 다음과 같은 방법을 고려하십시오.

case class Thing(id: Int, name: String)
val thing = Thing(1, "Apple")

thing.productIterator.foreach {
  case t: Int => println(s"I am Int: $t") case t: String => println(s"String, Do some stuff: $t")
  case t => println(s"Absurd: $t")
} 

코드는 Scastie 에서 실행됩니다 .