Saya ingin mendapatkan jenis variabel saat runtime. Bagaimana saya melakukan ini?
sumber
Saya ingin mendapatkan jenis variabel saat runtime. Bagaimana saya melakukan ini?
Jadi, secara tegas, "tipe variabel" selalu ada, dan dapat diteruskan sebagai parameter tipe. Sebagai contoh:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Tetapi tergantung pada apa yang ingin Anda lakukan , itu tidak akan membantu Anda. Misalnya, mungkin ingin tidak mengetahui apa tipe variabelnya, tetapi ingin mengetahui apakah tipe nilainya adalah tipe tertentu, seperti ini:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Di sini tidak masalah apa jenis variabelnya Any
,. Yang penting, yang dicentang adalah jenisnya 5
, nilainya. Faktanya, T
itu tidak berguna - Anda mungkin juga yang menulisnya def f(v: Any)
. Juga, ini menggunakan salah satu ClassTag
atau nilai Class
, yang dijelaskan di bawah, dan tidak dapat memeriksa parameter tipe dari suatu tipe: Anda dapat memeriksa apakah sesuatu adalah List[_]
( List
dari sesuatu), tetapi tidak apakah itu, misalnya, List[Int]
atau List[String]
.
Kemungkinan lain adalah Anda ingin merefleksikan tipe variabel. Yaitu, Anda ingin mengubah jenis menjadi nilai, sehingga Anda dapat menyimpannya, menyebarkannya, dll. Ini melibatkan refleksi, dan Anda akan menggunakan salah satu ClassTag
atau a TypeTag
. Sebagai contoh:
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
juga akan membiarkan Anda menggunakan parameter tipe yang Anda terima match
. Ini tidak akan berhasil:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Tapi ini akan:
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)
Di sini saya menggunakan sintaks batas konteksB : ClassTag
, yang berfungsi seperti parameter implisit dalam ClassTag
contoh sebelumnya , tetapi menggunakan variabel anonim.
Anda juga bisa mendapatkan ClassTag
nilai Class
, seperti ini:
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
dibatasi karena hanya mencakup kelas dasar, tetapi tidak jenis parameternya. Artinya, ClassTag
untuk List[Int]
dan List[String]
adalah sama List
,. Jika Anda membutuhkan parameter tipe, maka Anda harus menggunakan a TypeTag
. TypeTag
Namun, A tidak dapat diperoleh dari suatu nilai, juga tidak dapat digunakan pada pencocokan pola, karena penghapusan JVM .
Contoh dengan TypeTag
can menjadi sangat rumit - bahkan membandingkan dua jenis tag tidaklah sederhana, seperti yang dapat dilihat di bawah ini:
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
Tentu saja, ada cara untuk membuat perbandingan itu kembali menjadi kenyataan, tetapi itu akan membutuhkan beberapa bab buku untuk benar-benar dibahas TypeTag
, jadi saya akan berhenti di sini.
Terakhir, mungkin Anda sama sekali tidak peduli dengan jenis variabelnya. Mungkin Anda hanya ingin tahu apa itu kelas suatu nilai, dalam hal ini jawabannya agak sederhana:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Akan lebih baik, bagaimanapun, untuk lebih spesifik tentang apa yang ingin Anda capai, sehingga jawabannya bisa lebih tepat sasaran.
5
adalah turunan dariInt
dan turunan dariAny
. Selain itu, penjelasan Anda sempurna :)Int
adalahAny
, tetapiAny
tidakInt
. Ia bekerja pada Scala 2.10, dan seharusnya bekerja pada Scala 2.11, dan saya tidak tahu mengapa tidak.a match { case _: B => ...
menguji jenis nilai aktual variabela
, bukan jenis variabela
. Anda benar karena ia mengembalikan apa yang Anda katakan dalam skala 2.10.6. Tapi itu pasti bug. Dalam skala 2.11.8, jenis nilai aktual diuji sebagaimana mestinya.Saya pikir pertanyaannya tidak lengkap. jika Anda bermaksud bahwa Anda ingin mendapatkan informasi tipe dari beberapa kelas tipe maka di bawah ini:
Jika Anda ingin mencetak seperti yang Anda tentukan maka:
Jika Anda dalam mode repl maka
Atau jika Anda hanya ingin tahu apa jenis kelasnya maka seperti yang dijelaskan @monkjack
"string".getClass
mungkin bisa menyelesaikan tujuan tersebutsumber
typeof x
, di sinimanOf(x)
ucapkan tipe datanya!Jika jenis variabel yang Anda maksud adalah kelas runtime dari objek yang ditunjuk variabel, maka Anda bisa mendapatkan ini melalui referensi kelas yang dimiliki semua objek.
Namun jika yang Anda maksud adalah tipe variabel itu dideklarasikan sebagai, maka Anda tidak bisa mendapatkannya. Misalnya, jika Anda mengatakan
maka Anda masih akan mendapatkan
String
kembali dari kode di atas.sumber
name.getClass.getSimpleName
untuk hasil yang lebih mudah dibacaSaya telah mengujinya dan berhasil
sumber