使用类型参数键入cast

Fyn*_*ynn 11 reflection scala shapeless

给定是一个Java方法,它返回java.lang.Object给定字符串的s.我想将此方法包装在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
Run Code Online (Sandbox Code Playgroud)

(如何)使用Scala的反射API可以实现这一目标吗?我很清楚,convert可能必须改变签名.

Mil*_*bin 15

你可以尝试无形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
Run Code Online (Sandbox Code Playgroud)


gou*_*ama 13

那是一个ClassTagif for:

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
  }
}
Run Code Online (Sandbox Code Playgroud)

它可以用作提取器,同时测试和转换为合适的类型.

例:

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)
Run Code Online (Sandbox Code Playgroud)

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

迈尔斯的回答Typeable似乎是自动处理这些边缘情况.