我想写一个将任何类型转换为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中类型擦除的帖子和问题,但仍然无法获取它,具体解释会很有帮助!
答案 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/)