Saya ingin mendapatkan jenis variabel saat runtime. Bagaimana saya melakukan ini?
Jawaban:
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, Titu tidak berguna - Anda mungkin juga yang menulisnya def f(v: Any). Juga, ini menggunakan salah satu ClassTagatau nilai Class, yang dijelaskan di bawah, dan tidak dapat memeriksa parameter tipe dari suatu tipe: Anda dapat memeriksa apakah sesuatu adalah List[_]( Listdari 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 ClassTagatau 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 ClassTagjuga 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 ClassTagcontoh sebelumnya , tetapi menggunakan variabel anonim.
Anda juga bisa mendapatkan ClassTagnilai 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 ClassTagdibatasi karena hanya mencakup kelas dasar, tetapi tidak jenis parameternya. Artinya, ClassTaguntuk List[Int]dan List[String]adalah sama List,. Jika Anda membutuhkan parameter tipe, maka Anda harus menggunakan a TypeTag. TypeTagNamun, A tidak dapat diperoleh dari suatu nilai, juga tidak dapat digunakan pada pencocokan pola, karena penghapusan JVM .
Contoh dengan TypeTagcan 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.
Intadalah Any, tetapi Anytidak Int. 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 variabel a, bukan jenis variabel a. 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:
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]
Jika Anda dalam mode repl maka
scala> :type List(1,2,3)
List[Int]
Atau jika Anda hanya ingin tahu apa jenis kelasnya maka seperti yang dijelaskan @monkjack "string".getClassmungkin bisa menyelesaikan tujuan tersebut
typeof x, di sini manOf(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.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
Namun jika yang Anda maksud adalah tipe variabel itu dideklarasikan sebagai, maka Anda tidak bisa mendapatkannya. Misalnya, jika Anda mengatakan
val name: Object = "sam"
maka Anda masih akan mendapatkan Stringkembali dari kode di atas.
name.getClass.getSimpleNameuntuk hasil yang lebih mudah dibaca
Saya telah mengujinya dan berhasil
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5adalah turunan dariIntdan turunan dariAny. Selain itu, penjelasan Anda sempurna :)