2013-08-17 31 views
8

Cho trước là một phương thức Java trả về java.lang.Object s cho một chuỗi nhất định. Tôi muốn bọc phương thức này theo phương thức Scala để chuyển đổi các thể hiện được trả về thành một số loại T. Nếu chuyển đổi không thành công, phương thức sẽ trả về None. Tôi đang tìm một cái gì đó tương tự như thế này:Loại truyền bằng cách sử dụng tham số kiểu

def convert[T](key: String): Option[T] = { 
    val obj = someJavaMethod(key) 
    // return Some(obj) if obj is of type T, otherwise None 
} 

convert[Int]("keyToSomeInt") // yields Some(1) 
convert[String]("keyToSomeInt") // yields None 

(Làm thế nào) Điều này có thể đạt được bằng cách sử dụng API phản chiếu của Scala không? Tôi biết rõ rằng chữ ký của convert có thể phải được thay đổi.

Trả lời

12

Đó là những gì một ClassTag nếu vì:

import reflect.ClassTag 

def convert[T : ClassTag](key: String): Option[T] = { 
    val ct = implicitly[ClassTag[T]] 
    someJavaMethod(key) match { 
    case ct(x) => Some(x) 
    case _ => None 
    } 
} 

Nó có thể được sử dụng như một vắt để kiểm tra và dàn diễn viên với loại thích hợp cùng một lúc.

Ví dụ:

scala> def someJavaMethod(s: String): AnyRef = "e" 
someJavaMethod: (s: String)AnyRef 

[...] 

scala> convert[Int]("key") 
res4: Option[Int] = None 

scala> convert[String]("key") 
res5: Option[String] = Some(e) 

Sửa: lưu ý rằng, một ClassTag không không nguyên thủy đóng hộp tự động Unbox. Vì vậy, ví dụ: convert[Int]("a") sẽ không bao giờ hoạt động, bởi vì phương thức java trả về AnyRef, nó sẽ phải là convert[java.lang.Integer]("a"), v.v. đối với các loại nguyên thủy khác.

Câu trả lời của Miles với Typeable dường như tự động xử lý các trường hợp cạnh đó.

15

Bạn có thể thử shapeless 's Typeable,

scala> import shapeless._ ; import syntax.typeable._ 
import shapeless._ 
import syntax.typeable._ 

scala> def someJavaMethod(key: String): AnyRef = 
    | key match { 
    |  case "keyToSomeInt" => 23.asInstanceOf[AnyRef] 
    |  case "keyToSomeString" => "foo" 
    | } 
someJavaMethod: (key: String)AnyRef 

scala> def convert[T: Typeable](key: String): Option[T] = 
    | someJavaMethod(key).cast[T] 
convert: [T](key: String)(implicit evidence$1: shapeless.Typeable[T])Option[T] 

scala> convert[Int]("keyToSomeInt") 
res0: Option[Int] = Some(23) 

scala> convert[String]("keyToSomeString") 
res1: Option[String] = Some(foo) 

scala> convert[String]("keyToSomeInt") 
res2: Option[String] = None 

scala> convert[Int]("keyToSomeString") 
res3: Option[Int] = None 
+0

Cảm ơn rất nhiều cho việc này. Tôi đã tạo ra 'safeCast [T: ClassTag]' của riêng mình trên một chuyển đổi ngầm từ Option [Any] nhưng nhận thấy các nguyên thủy luôn quay trở lại None. Sử dụng Typeable Tôi đã thay đổi phần thân thành một 'opt.flatMap đơn giản (_. Cast [T])' và nó hoạt động rất tốt. – ShawnFumo

Các vấn đề liên quan