2013-10-15 17 views

Trả lời

95

vì vậy, nói đúng, "loại của một biến "luôn luôn hiện diện, và có thể được truyền xung quanh như một tham số kiểu. Ví dụ:

val x = 5 
def f[T](v: T) = v 
f(x) // T is Int, the type of x 

Nhưng tùy thuộc vào những gì bạn muốn làm , điều đó sẽ không giúp bạn. Ví dụ, có thể muốn không biết loại của biến là gì, nhưng biết nếu loại của giá trị là một số loại hình cụ thể, chẳng hạn như thế này:

val x: Any = 5 
def f[T](v: T) = v match { 
    case _: Int => "Int" 
    case _: String => "String" 
    case _   => "Unknown" 
} 
f(x) 

Ở đây nó không có vấn đề gì là loại biến, Any. Những gì quan trọng, những gì được kiểm tra là loại 5, giá trị. Thực tế, T là vô ích - bạn có thể đã viết nó def f(v: Any) thay thế. Ngoài ra, điều này sử dụng hoặc là ClassTag hoặc giá trị Class, được giải thích bên dưới và không thể kiểm tra thông số loại của một loại: bạn có thể kiểm tra xem có gì đó là List[_] (List của một thứ gì đó), nhưng không List[Int] hoặc List[String].

Một khả năng khác là bạn muốn chỉnh sửa loại biến. Tức là, bạn muốn chuyển đổi loại thành một giá trị, vì vậy bạn có thể lưu trữ nó, vượt qua nó, vv Điều này liên quan đến sự phản ánh, và bạn sẽ sử dụng hoặc ClassTag hoặc TypeTag. Ví dụ:

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 cũng sẽ cho phép bạn sử dụng thông số loại bạn nhận được trên match.Điều này sẽ không làm việc:

def f[A, B](a: A, b: B) = a match { 
    case _: B => "A is a B" 
    case _ => "A is not a B" 
} 

Nhưng điều này sẽ:

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) 

Ở đây tôi đang sử dụng bối cảnh tiếp giáp cú pháp, B : ClassTag, mà hoạt động giống như các tham số ngầm định trong hợp ClassTag ví dụ trước , nhưng sử dụng biến ẩn danh.

Người ta cũng có thể nhận được một ClassTag từ một giá trị của Class, như thế này:

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 

Một ClassTag được giới hạn ở chỗ nó chỉ bao gồm các lớp cơ sở, nhưng không tham số kiểu của nó. Tức là, ClassTag cho List[Int]List[String] giống nhau, List. Nếu bạn cần thông số loại, thì bạn phải sử dụng một số TypeTag thay thế. Tuy nhiên, không thể lấy giá trị TypeTag từ giá trị, cũng như không thể sử dụng trên kết hợp mẫu, do xóa của JVM.

Ví dụ với TypeTag có thể nhận được khá phức tạp - thậm chí không so sánh hai loại thẻ là không chính xác đơn giản, như có thể thấy dưới đây:

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 

Tất nhiên, có nhiều cách để thực hiện so sánh mà trở thành sự thật, nhưng nó sẽ yêu cầu một vài chương sách thực sự bao gồm TypeTag, vì vậy tôi sẽ dừng lại ở đây.

Cuối cùng, có thể bạn không quan tâm đến loại biến nào cả. Có lẽ bạn chỉ muốn biết lớp của một giá trị, trong trường hợp câu trả lời là khá đơn giản là những gì:

val x = 5 
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it 

Sẽ tốt hơn, tuy nhiên, để cụ thể hơn về những gì bạn muốn đạt được, do đó câu trả lời có thể được thêm vào vấn đề.

+0

Đoạn mã ví dụ bạn đã viết sau khi "Nhưng điều này sẽ:" là khó hiểu. Nó biên dịch nhưng kết quả không phải là kết quả bạn hiển thị trong phần bình luận. Cả hai cuộc gọi đều trả về cùng một kết quả: "A là B". Bởi vì giá trị '5' là cả một thể hiện của' Int' và một thể hiện của 'Bất kỳ'. Ngoài ra, lời giải thích của bạn là hoàn hảo :) – Readren

+0

@Readren Giá trị không được kiểm tra, lớp đó là. 'Int' là' Any', nhưng 'Bất kỳ' không phải là' Int'. Nó hoạt động trên Scala 2.10, và nó _should_ làm việc trên Scala 2.11, và tôi không biết tại sao nó không phải là. –

+1

Nó làm tôi sợ mâu thuẫn với một eminence như bạn, nhưng mã 'a match {case _: B => ...' kiểm tra kiểu giá trị thực của biến 'a', không phải kiểu biến' a' '. Bạn có quyền trả lời những gì bạn nói trong scala 2.10.6. Nhưng nó phải là một lỗi. Trong scala 2.11.8 loại giá trị thực tế được kiểm tra, như nó cần. – Readren

14

Nếu bằng loại biến bạn có nghĩa là lớp thời gian chạy của đối tượng mà biến trỏ đến, thì bạn có thể nhận được điều này thông qua tham chiếu lớp mà tất cả các đối tượng đều có.

val name = "sam"; 
name: java.lang.String = sam 
name.getClass 
res0: java.lang.Class[_] = class java.lang.String 

Nếu bạn có nghĩa là loại biến được khai báo là, thì bạn không thể nhận được biến đó. Ví dụ: nếu bạn nói

val name: Object = "sam" 

thì bạn vẫn sẽ nhận được String trở lại từ mã trên.

+1

Bạn cũng có thể làm 'name.getClass.getSimpleName' cho một đầu ra dễ đọc hơn –

31

Tôi nghĩ câu hỏi chưa hoàn chỉnh. nếu bạn có nghĩa là bạn muốn để có được các loại thông tin của một số typeclass sau đó dưới đây:

Nếu bạn muốn in như bạn đã xác định rồi:

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] 

Nếu bạn đang ở trong chế độ repl sau đó

scala> :type List(1,2,3) 
List[Int] 

Hoặc nếu bạn chỉ muốn biết những gì lớp gõ sau đó là @monkjack giải thích "string".getClass có thể giải quyết mục đích

6

tôi đã thử nghiệm điều đó và nó làm việc

val x = 9 
def printType[T](x:T) :Unit = {println(x.getClass.toString())} 
Các vấn đề liên quan