我想模式匹配一个函数,问题是类型擦除 . 请注意,在下面的代码段中,尽管发出了警告,但发生了匹配,并且在此处发生了一个匹配 .
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>
我能想出的是一个包含该功能的案例类 . 我得到了类型安全,请注意下面的错误 . But ,这首先是不优雅的,第二,我不是 . 我唯一的猜测是case类受编译器保护,并且只在运行时解析匹配
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
总而言之,我想知道是否有一种优雅的模式匹配函数的方法,也许可以理解为什么上面的例子像他们那样做了
2 回答
简短的回答:你必须撤消擦除,用
TypeTag
来表示类型 .因为您的case类没有类型参数 . 只删除泛型类型,这就是它被称为“部分擦除”的原因 .
相关问题:Generic unapply method for different types of List . 以下代码与其中一个答案基本相同,但使用函数而不是列表:
我不确定是否有办法编写一个提取器来使匹配块更好 .
如果您需要以丢失静态类型信息的方式传递这些函数(将它们推送到
Function[_, _]
的集合中,然后将其用作Akka消息等),那么您还需要传递标记:这里的警告实际上是双重的:
1)首先,"a value of type () => Boolean cannot also be a () => String":事实上你正在匹配
() => Boolean
并且它永远不会同时() => String
所以情况没有意义,并且理想世界永远不应该匹配 . 然而,第二部分提示,擦除开始发挥作用2)"(but still might match its erasure)":这里的擦除意味着
() => Boolean
(又名Function0[Boolean]
)的实例和() => String
(又名Function0[String]
)的实例在运行时表示完全相同 . 因此,没有办法区分它们,当你模式匹配Function0[String]
实际上编译器只能告诉它是 someFunction0
但不知道它是Function0[Boolean]
还是Function0[String]
.在这里很容易错过警告的第二部分 . 如果
fl
被输入Any
,警告的第一部分将不适用,您将获得更有用的消息:至于解决方案,除了确实包装函数实例之外,你几乎无能为力 . 幸运的是,您不需要为每种可能的返回类型编写一个特定的包装器 . Scala提供
ClassTag
和TypeTag
来解决擦除问题,我们可以通过将其存储在(通用)函数包装器中来利用它 . 然而,它仍然是相当麻烦的使用,并且在不安全方面是错误的,因为你必须匹配存储在包装器内的ClassTag
/TypeTag
,并且(直接通过asInstanceOf
或通过相同的模式匹配间接)功能到相应的功能类型 .