【问题标题】:Type casting using type parameter使用类型参数进行类型转换
【发布时间】:2022-03-11 23:53:58
【问题描述】:

Given 是一个 Java 方法,它为给定的字符串返回 java.lang.Objects。我想将此方法包装在 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 的签名可能需要更改。

【问题讨论】:

    标签: scala reflection shapeless


    【解决方案1】:

    你可以试试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
    

    【讨论】:

    • 非常感谢。我在 Option[Any] 的隐式转换上创建了自己的safeCast[T: ClassTag],但注意到原语总是返回 None。使用 Typeable,我将正文更改为简单的 opt.flatMap(_.cast[T]),效果很好。
    【解决方案2】:

    这就是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"),对于其他原始类型,依此类推。

    Miles 对Typeable 的回答似乎自动处理了这些极端情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      相关资源
      最近更新 更多