Çalışma zamanında bir değişkenin türünü almak istiyorum. Bunu nasıl yaparım?
Yanıtlar:
Yani, kesin olarak söylemek gerekirse, "değişken türü" her zaman mevcuttur ve bir tür parametresi olarak aktarılabilir. Örneğin:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
Ancak ne yapmak istediğinize bağlı olarak , bu size yardımcı olmayacaktır. Örneğin, değişkenin türünün ne olduğunu bilmek istemeyebilir, ancak değerin türünün aşağıdaki gibi belirli bir tür olup olmadığını bilmek isteyebilirsiniz :
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
Burada değişkenin türünün ne olduğu önemli değil Any. Önemli olan, kontrol edilen şeyin türü 5, değeridir. Aslında Tişe yaramaz - onun def f(v: Any)yerine yazmış olabilirsin . Ayrıca, bu aşağıda açıklanan ClassTagdeğerlerden birini veya değerini kullanır Classve bir türün tip parametrelerini kontrol edemez: bir şeyin List[_]( Listbir şeyin) olup olmadığını kontrol edebilirsiniz , ancak örneğin a List[Int]veya olup olmadığını kontrol edemezsiniz List[String].
Diğer bir olasılık, değişkenin türünü yeniden belirtmek istemenizdir . Yani, türü bir değere dönüştürmek istersiniz, böylece onu saklayabilir, başka bir yere aktarabilirsiniz. Bu yansıma içerir ve ya ya ClassTagda a kullanacaksınız TypeTag. Örneğin:
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 ClassTagayrıca aldığınız tür parametrelerini kullanmanıza izin verir match. Bu işe yaramaz:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
Ancak bu:
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)
Burada , önceki örnekteki örtük parametre gibi çalışan , ancak anonim bir değişken kullanan bağlam sınırları sözdizimini kullanıyorum.B : ClassTagClassTag
Bir de ClassTagbir değerden şu şekilde bir alabilir 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, yalnızca temel sınıfı kapsaması, ancak tür parametrelerini kapsamaması açısından sınırlıdır. Yani, ClassTagfor List[Int]ve List[String]aynıdır List. Tür parametrelerine ihtiyacınız varsa, TypeTagbunun yerine a kullanmanız gerekir . Bir TypeTagnedeniyle JVM, ancak, bir değerden elde edilemez, ne de bir desen maç kullanılabilir silinmeye .
Örnekler TypeTagoldukça karmaşık olabilir - iki tip etiketi karşılaştırmak bile aşağıda görülebileceği gibi tam olarak basit değildir:
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
Elbette, bu karşılaştırmayı gerçeğe dönüştürmenin yolları var, ancak gerçekten ele almak için birkaç kitap bölümü gerektirecek TypeTag, bu yüzden burada duracağım.
Son olarak, belki de değişkenin türünü hiç umursamıyorsunuzdur. Belki sadece bir değerin sınıfının ne olduğunu bilmek istersiniz, bu durumda cevap oldukça basittir:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
Bununla birlikte, neyi başarmak istediğiniz konusunda daha net olmanız daha iyi olur, böylece cevap daha doğru olabilir.
Intolduğunu Any, ancak Anydeğildir Int. Scala 2.10 üzerinde çalışıyor ve Scala 2.11 üzerinde çalışıyor olmalı ve neden olmadığını bilmiyorum.
a match { case _: B => ...değişkenin atürünü değil, değişkenin gerçek değerinin türünü test ediyor a. Ölçek 2.10.6'da söylediklerinizi döndürdüğü konusunda haklısınız. Ama bir hata olmalı. Ölçek 2.11.8'de, olması gerektiği gibi gerçek değerin türü test edilir.
Bence soru eksik. Bazı tip sınıflarının tür bilgilerini almak istediğinizi kastetmişseniz, aşağıdan:
Belirttiğiniz gibi yazdırmak isterseniz, o zaman:
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]
Eğer repl modundaysanız o zaman
scala> :type List(1,2,3)
List[Int]
Veya sadece sınıfın türünü öğrenmek istiyorsanız @monkjack'in açıkladığı gibi "string".getClassamacı çözebilir
typeof x, burada manOf(x)veri türünü söyleyin!
Tarafından Eğer bir değişkenin türü nesnenin çalışma zamanı sınıfını anlamında değişken puan, o zaman tüm nesneler olduğunu sınıf referansı ile bu alabilirsiniz.
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
Bununla birlikte, değişkenin bildirildiği türü kastediyorsanız, bunu anlayamazsınız. Örneğin, diyorsan
val name: Object = "sam"
o zaman Stringyukarıdaki koddan yine de bir geri alacaksınız .
name.getClass.getSimpleNameDaha okunaklı bir çıktı için de yapabilirsiniz
bunu test ettim ve işe yaradı
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5hem örneği hem deIntörneğidirAny. Bunun dışında açıklamanız mükemmeldi :)