ฉันต้องการรับประเภทของตัวแปรที่รันไทม์ ฉันต้องทำอย่างไร
ฉันต้องการรับประเภทของตัวแปรที่รันไทม์ ฉันต้องทำอย่างไร
คำตอบ:
ดังนั้นพูดอย่างเคร่งครัด "ประเภทของตัวแปร" จะปรากฏอยู่เสมอและสามารถส่งผ่านเป็นพารามิเตอร์ประเภทได้ ตัวอย่างเช่น:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
แต่ขึ้นอยู่กับสิ่งที่คุณต้องการทำนั่นจะไม่ช่วยคุณ ตัวอย่างเช่นอาจไม่ต้องการทราบว่าประเภทของตัวแปรคืออะไร แต่ต้องการทราบว่าประเภทของค่าเป็นประเภทเฉพาะเช่นนี้หรือไม่:
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
ที่นี่ไม่สำคัญว่าตัวแปรจะเป็นประเภทAny
ใด สิ่งที่สำคัญสิ่งที่ตรวจสอบคือประเภทของ5
ค่า ในความเป็นจริงT
ไม่มีประโยชน์ - คุณอาจเขียนมันdef f(v: Any)
แทนก็ได้เช่นกัน นอกจากนี้สิ่งนี้ใช้อย่างใดอย่างหนึ่งClassTag
หรือค่าClass
ซึ่งอธิบายไว้ด้านล่างและไม่สามารถตรวจสอบพารามิเตอร์ประเภทของประเภท: คุณสามารถตรวจสอบได้ว่าบางสิ่งเป็นList[_]
( List
ของบางสิ่ง) หรือไม่ แต่ไม่ว่าจะเป็นเช่น a List[Int]
หรือList[String]
.
ความเป็นไปได้อีกประการหนึ่งคือคุณต้องการระบุประเภทของตัวแปรอีกครั้ง นั่นคือคุณต้องการแปลงชนิดเป็นค่าเพื่อให้คุณสามารถเก็บไว้ผ่านมันไปรอบ ๆ ฯลฯ นี้เกี่ยวข้องกับการสะท้อนและคุณจะใช้อย่างใดอย่างหนึ่งหรือClassTag
TypeTag
ตัวอย่างเช่น:
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"
ยังจะช่วยให้คุณใช้พารามิเตอร์ชนิดที่คุณได้รับในClassTag
match
สิ่งนี้ใช้ไม่ได้:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
แต่สิ่งนี้จะ:
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)
ที่นี่ฉันใช้ไวยากรณ์ขอบเขตบริบทB : ClassTag
ซึ่งทำงานเหมือนกับพารามิเตอร์นัยในClassTag
ตัวอย่างก่อนหน้านี้แต่ใช้ตัวแปรที่ไม่ระบุชื่อ
เราสามารถรับ a ClassTag
จากค่าได้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
มีข้อ จำกัด ที่ครอบคลุมเฉพาะคลาสพื้นฐานเท่านั้น แต่ไม่ครอบคลุมพารามิเตอร์ประเภท นั่นคือClassTag
สำหรับList[Int]
และเป็นเหมือนกันList[String]
List
หากคุณต้องการพารามิเตอร์ประเภทคุณต้องใช้TypeTag
แทน TypeTag
แต่ไม่สามารถหาได้จากค่าหรือสามารถที่จะนำมาใช้ในการแข่งขันรูปแบบเนื่องจาก JVM ของการลบออก
ตัวอย่างที่มีTypeTag
อาจค่อนข้างซับซ้อน - การไม่เปรียบเทียบแท็กสองประเภทนั้นไม่ใช่เรื่องง่ายอย่างที่เห็นด้านล่าง:
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
แน่นอนว่ามีหลายวิธีที่จะทำให้การเปรียบเทียบนั้นกลับมาเป็นจริงได้ แต่ต้องใช้หนังสือสองสามบทเพื่อให้ครอบคลุมจริงๆTypeTag
ฉันจะหยุดตรงนี้
สุดท้ายบางทีคุณอาจไม่สนใจประเภทของตัวแปรเลย บางทีคุณอาจแค่อยากรู้ว่าคลาสของค่าคืออะไรซึ่งในกรณีนี้คำตอบนั้นค่อนข้างง่าย:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
อย่างไรก็ตามจะเป็นการดีกว่าหากเจาะจงมากขึ้นเกี่ยวกับสิ่งที่คุณต้องการทำให้สำเร็จเพื่อให้คำตอบตรงประเด็นมากขึ้น
Int
เป็นAny
แต่ไม่ได้เป็นAny
Int
มันใช้งานได้กับ Scala 2.10 และควรใช้กับ Scala 2.11 และฉันไม่รู้ว่าทำไมถึงไม่เป็นเช่นนั้น
a match { case _: B => ...
ทดสอบประเภทของค่าจริงของตัวแปรไม่ประเภทของตัวแปรa
a
คุณพูดถูกที่มันจะส่งคืนสิ่งที่คุณพูดใน scala 2.10.6 แต่น่าจะเป็นบั๊ก ใน scala 2.11.8 จะมีการทดสอบประเภทของค่าจริงตามที่ควร
ฉันคิดว่าคำถามไม่สมบูรณ์ หากคุณหมายถึงว่าคุณต้องการรับข้อมูลประเภทของคลาสประเภทบางประเภทจากด้านล่าง:
หากคุณต้องการพิมพ์ตามที่ระบุไว้:
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]
หากคุณอยู่ในโหมดจำลองแล้ว
scala> :type List(1,2,3)
List[Int]
หรือหากคุณต้องการทราบว่าประเภทของชั้นเรียนเป็นอย่างไรตามที่ @monkjack อธิบายไว้"string".getClass
อาจช่วยแก้จุดประสงค์ได้
typeof x
นี่manOf(x)
คือประเภทข้อมูล!
หากตามประเภทของตัวแปรคุณหมายถึงคลาสรันไทม์ของอ็อบเจ็กต์ที่ตัวแปรชี้ไปคุณจะได้รับสิ่งนี้ผ่านการอ้างอิงคลาสที่อ็อบเจ็กต์ทั้งหมดมี
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
อย่างไรก็ตามหากคุณหมายถึงประเภทที่มีการประกาศตัวแปรคุณจะไม่สามารถรับสิ่งนั้นได้ เช่นถ้าคุณพูด
val name: Object = "sam"
จากนั้นคุณจะยังคงได้รับString
คืนจากรหัสด้านบน
name.getClass.getSimpleName
เพื่อให้ได้ผลลัพธ์ที่อ่านได้มากขึ้น
ฉันได้ทดสอบแล้วและได้ผล
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5
เป็นทั้งตัวอย่างของและเป็นตัวอย่างของInt
Any
นอกเหนือจากนั้นคำอธิบายของคุณก็สมบูรณ์แบบ :)