Scala的通用toOption无法按预期工作

时间:2017-01-24 21:25:07

标签: scala

我想写一个将任何类型转换为Option[T]的通用函数 但不知怎的,它没有按预期工作

scala> def toOption[T](obj:Any):Option[T] = obj match {
 |   case obj:T => Some(obj)
 |   case _ => None
 | }
<console>:11: warning: abstract type pattern T is unchecked since it is eliminated by erasure
     case obj:T => Some(obj)
              ^
 toOption: [T](obj: Any)Option[T]

这里似乎可以返回Option[String]

scala> toOption[String]("abc")
res0: Option[String] = Some(abc)

但此处返回Some(def)而不是None

scala> toOption[Int]("def")
res1: Option[Int] = Some(def)

我似乎无法找到创建此泛型函数的合适方法,也无法理解为什么会发生这种情况,我已经阅读了许多有关scala中类型擦除的帖子和问题,但仍然无法获取它,具体解释会很有帮助!

2 个答案:

答案 0 :(得分:2)

类型T在运行时不可用,因为Scala对Java这样的泛型使用类型擦除。所以你的测试case obj:T没有达到预期的效果,编译器警告你这个事实。

您可以使用ClassTag在运行时提供类型信息。 ClassTag已在其unapply方法中实现了对Optional的转换:

scala> import scala.reflect.{classTag,ClassTag};
import scala.reflect.{classTag, ClassTag}

scala> def toOption[T: ClassTag](obj: Any): Option[T] = classTag[T].unapply(obj);
toOption: [T](obj: Any)(implicit evidence$1: scala.reflect.ClassTag[T])Option[T]

scala> toOption[Int](1)
res1: Option[Int] = Some(1)

scala> toOption[String](1)
res2: Option[String] = None

scala> toOption[String]("one")
res3: Option[String] = Some(one)

scala> toOption[Int]("one")
res4: Option[Int] = None

但是这不适用于泛型类型,如下所示:

scala> toOption[List[Int]](List("one", "two"))
res5: Option[List[Int]] = Some(List(one, two))

scala> res5.get
res6: List[Int] = List(one, two)

scala> res6(0) + res6(1)
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
  at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
  ... 29 elided

答案 1 :(得分:0)

您可能希望函数有两个类型参数 - 所需类型和实际类型:

BAD_EXEC

然后,我想,只有在类型匹配时才要返回def toOption[Desired, Actual](obj:Actual):Option[Desired] = ???

Some

这里有两个类型参数,当Scala无法推断出两个参数时,它们有时可能不方便。对于与您使用的语法相同(给出单一类型参数),您可以使用以下技巧:

def toOption[Desired, Actual](obj:Actual)
  (implicit ev: Actual =:= Desired = null):Option[Desired] = 
  if(ev == null) 
    None
  else
    Some(ev(obj))

它可能以相同的方式使用:

class toOptionImpl[Desired] {
  def apply[Desired, Actual](obj:Actual)
    (implicit ev: Actual =:= Desired = null):Option[Desired] = 
    if(ev == null) 
      None
    else
      Some(ev(obj))
}
def toOption[Desired] = new toOptionImpl[Desired]

(您也可以查看Miles Sabin的多态函数https://milessabin.com/blog/2012/04/27/shapeless-polymorphic-function-values-1/https://milessabin.com/blog/2012/05/10/shapeless-polymorphic-function-values-2/