2013-08-17 50 views
8

鉴于给定的Java方法返回给定字符串的java.lang.Object。我想将这个方法包装在一个Scala方法中,该方法将返回的实例转换为某种类型的T。如果转换失败,该方法应返回None。我正在寻找类似的东西:使用类型参数进行类型转换

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 

(如何)这可以实现使用Scala的反射API?我很清楚,convert的签名可能不得不改变。

回答

12

这就是一个ClassTag如果:

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

它可以被用作提取测试和转换为在同一时间正确的类型。

例子:

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) 

编辑:但是请注意,一个ClassTag自动拆箱装箱元。因此,例如,convert[Int]("a")将永远不会工作,因为java方法返回AnyRef,它必须是convert[java.lang.Integer]("a"),对其他基元类型也是如此。

迈尔斯的回答Typeable似乎自动照顾这些边缘情况。

15

你可以尝试shapelessTypeable

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

非常感谢这一点。我从Option [Any]的隐式转换中创建了自己的'safeCast [T:ClassTag]',但注意到原语总是返回None。使用Typeable我将主体改为了一个简单的'opt.flatMap(_。cast [T])',它效果很好。 – ShawnFumo

相关问题