2013-08-17 22 views
8

Podana jest metoda Java, która zwraca java.lang.Object s dla danego ciągu znaków. Chciałbym zawrzeć tę metodę w metodzie Scala, która konwertuje zwracane instancje do pewnego typu T. Jeśli konwersja nie powiedzie się, metoda powinna zwrócić None. Szukam coś podobnego do tego:Odlewanie za pomocą parametru typu

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 

(Jak) Można to osiągnąć za pomocą Scala odbicie API? Mam świadomość, że podpis convert może wymagać zmiany.

Odpowiedz

12

To co ClassTag jeśli dla:

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 
    } 
} 

To może być stosowany jako ekstraktor do przetestowania i obsady do odpowiedniego typu w tym samym czasie.

Przykład:

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) 

Edit: jednak pamiętać, że ClassTag robi nie automatycznie unbox zapakowane prymitywów. Na przykład: convert[Int]("a") nigdy nie zadziała, ponieważ metoda java zwróci AnyRef, musiałaby to być convert[java.lang.Integer]("a") itd. Dla innych typów pierwotnych.

Wydaje się, że odpowiedź Milesa z Typeable automatycznie zajmuje się tymi przypadkami brzegowymi.

15

Można spróbować 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

Dzięki tak dużo za to. Zrobiłem własny "safeCast [T: ClassTag]" na niejawnej konwersji z Opcji [Any], ale zauważyłem, że prymitywy zawsze zwracały Brak. Używając Typeable I zmieniłem body na prostą 'opt.flatMap (_. Cast [T])' i działa świetnie. – ShawnFumo

Powiązane problemy