Ç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 T
işe yaramaz - onun def f(v: Any)
yerine yazmış olabilirsin . Ayrıca, bu aşağıda açıklanan ClassTag
değerlerden birini veya değerini kullanır Class
ve bir türün tip parametrelerini kontrol edemez: bir şeyin List[_]
( List
bir ş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 ClassTag
da 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 ClassTag
ayrı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 : ClassTag
ClassTag
Bir de ClassTag
bir 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, ClassTag
for List[Int]
ve List[String]
aynıdır List
. Tür parametrelerine ihtiyacınız varsa, TypeTag
bunun yerine a kullanmanız gerekir . Bir TypeTag
nedeniyle JVM, ancak, bir değerden elde edilemez, ne de bir desen maç kullanılabilir silinmeye .
Örnekler TypeTag
oldukç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.
Int
olduğunu Any
, ancak Any
değ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 a
tü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".getClass
amacı çö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 String
yukarıdaki koddan yine de bir geri alacaksınız .
name.getClass.getSimpleName
Daha 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())}
5
hem örneği hem deInt
örneğidirAny
. Bunun dışında açıklamanız mükemmeldi :)