我想要模式匹配一个函数,问题是类型删除。请注意,在下面的代码片段中,尽管发出了警告,但仍然发生了匹配,并且出现了“错误”的匹配。
scala> def f1 = ()=>true
f1: () => Boolean
scala> val fl = f1
fl: () => Boolean = <function0>
scala>
scala> fl match {
| case fp :Function0[Boolean] => 1
| case _ => 2
| }
res8: Int = 1
scala>
scala> fl match {
| case fp :Function0[String] => 1
| case _ => 2
| }
<console>:11: warning: fruitless type test: a value of type () => Boolean cannot also be a () => String (but still might match its erasure)
case fp :Function0[String] => 1
^
res9: Int = 1
scala>
我能想到的是一个包装该函数的案例类。我得到了类型安全,请注意下面的错误。 但是,首先,这是不优雅的,其次,我不明白案例类如何强制类型,而模式匹配却不能。我唯一的猜测是案例类受编译器保护,并且匹配仅在运行时解析
scala> case class FunctionWrapper(fn: ()=>Boolean)
defined class FunctionWrapper
scala> val fw = FunctionWrapper(fl)
fw: FunctionWrapper = FunctionWrapper(<function0>)
scala> def fs = ()=>"whatever"
fs: () => String
scala> val fws = FunctionWrapper(fs)
<console>:10: error: type mismatch;
found : () => String
required: () => Boolean
val fws = FunctionWrapper(fs)
^
scala> fw match {
| case FunctionWrapper(f) => f()
| case _ => false
| }
res10: Boolean = true
总而言之,我想知道是否有一种优雅的方法来模式匹配函数,并且也许理解为什么上面的示例会这样做
最佳答案
简短的回答:您必须通过使用 TypeTag
来具体化类型来撤消删除。
I don't understand how the case class can enforce types whereas the pattern match can't.
因为你的案例类没有类型参数。仅删除泛型类型,这就是为什么它被称为“部分删除”。
相关问题:Generic unapply method for different types of List 。以下代码本质上与其中的答案之一相同,但使用函数而不是列表:
import scala.reflect.runtime.universe._
def foo[A : TypeTag](a: A): Int = typeOf[A] match {
case t if t =:= typeOf[Int => Int] => a.asInstanceOf[Int => Int](0)
case t if t =:= typeOf[Boolean => Int] => a.asInstanceOf[Boolean => Int](true)
case _ => 3
}
foo((i: Int) => i + 1)
// res0: Int = 1
foo((b: Boolean) => if (b) 2 else 0)
// res1: Int = 2
foo((b: Boolean) => !b)
// res2: Int = 3
我不确定是否有办法编写一个提取器来使匹配 block 更好。
如果您需要以丢失静态类型信息的方式传递这些函数(将它们插入 Function[_, _]
集合,然后将其用作 Akka 消息等),那么您还需要传递标签:
import scala.reflect.runtime.universe._
case class Tagged[A](a: A)(implicit val tag: TypeTag[A])
def foo[A, B](tagged: Tagged[A => B]): Int = tagged.tag.tpe match {
case t if t =:= typeOf[Int => Int] => tagged.a.asInstanceOf[Int => Int](0)
case t if t =:= typeOf[Boolean => Int] => tagged.a.asInstanceOf[Boolean => Int](true)
case _ => 3
}
foo(Tagged((i: Int) => i + 1))
// res0: Int = 1
foo(Tagged((b: Boolean) => if (b) 2 else 0))
// res1: Int = 2
foo(Tagged((b: Boolean) => !b))
// res2: Int = 3
关于function - scala 模式匹配函数 - 如何绕过类型删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32246734/