Bagaimana menemukan tipe data parameter kelas saat runtime dalam skala
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")
}
Tidak bisa mencerna mengapa hasilnya Absurd
bukan I am int
?
Tujuan saya adalah untuk mengetahui jenis data parameter kelas pada waktu proses dan mencocokkannya dengan jenis yang telah ditentukan.
Jawaban
Keduanya terkini dataType
dan typeOf[Int]
dicetak seolah- Int
olah tetapi jika Anda melakukannya showRaw
Anda akan melihat mengapa mereka tidak cocok
showRaw(dataType) // NullaryMethodType(TypeRef(ThisType(scala), scala.Int, List()))
showRaw(typeOf[Int]) // TypeRef(ThisType(scala), scala.Int, List())
Masalahnya adalah hanya tipe Int
dan tipe metode nullary yang dikembalikan Int
adalah tipe yang berbeda.
Coba tambahkan .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
Perlu juga disebutkan bahwa .decl(TermName("id"))
mengembalikan simbol pengambil, itu .decl(TermName("id "))
(dengan spasi kosong) yang mengembalikan simbol bidang. Jadi sebagai alternatif Anda dapat melakukannya dengan spasi kosong di nama simbol dan tanpa.resultType
val dataType = getType(thing).decl(TermName("id ")).asTerm.typeSignature
Aku akan menambah @TomerShetah 's jawaban bahwa jika tujuannya adalah 'pola pencocokan' semua bidang kelas kasus maka ini dapat dilakukan juga pada waktu kompilasi (kebanyakan) dengan tak berbentuk :
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
Jawaban @Dmytrio adalah penjelasan yang bagus mengapa refleksi tidak berfungsi seperti yang Anda harapkan.
Saya dapat memahami dari pertanyaan Anda, bahwa apa yang Anda coba lakukan, sebenarnya adalah pola yang cocok dengan semua variabel yang Anda miliki di kelas kasus. Harap pertimbangkan untuk melakukannya dengan cara berikut:
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")
}
Kode dijalankan di Scastie .