给出以下类型和实例:
type operation = (Int, Int) => Int
def add: operation = _ + _
如果我尝试匹配case语句中的操作,Scala会因为类型擦除而抱怨未经检查的输入:
for (a <- elements) a match {
case o: operation => // do stuff
}
在case语句中是否有一种方法可以实现这种基于函数的输入,同时具有易擦除性?
注意,这类似于this thread。
答案 0 :(得分:7)
处理类型擦除的一种简单方法是创建一个非完整的类。它并不完美,但它确实有效。使它成为一个扩展Function2的案例类,它甚至不太笨重,无法直接使用或模式匹配
scala> case class Operation(f : (Int,Int) => Int) extends ((Int,Int) => Int) {
| def apply(x : Int, y : Int) = f(x,y)
| }
defined class Operation
scala> def add = Operation(_ + _)
add: Operation
scala> val y = add(7,3)
y: Int = 10
scala> val elements = List(1, add, 2)
elements: List[Any] = List(1, <function2>, 2)
scala> for (a <- elements) yield a match {
| case Operation(f) => f(1,2)
| case x : Int => x
| }
res0: List[Int] = List(1, 3, 2)
限制是你必须在失去类型之前“装箱”操作,而不是之后。此外,每个具体的函数类型最终会有一个类。
另一个可以说更好的解决方案是不丢失类型信息。使用Either保留静态类型信息。
scala> val elements : List[Either[Int, (Int, Int) => Int]] = List(Left(1), Right(_ + _), Left(2))
elements: List[Either[Int,(Int, Int) => Int]] = List(Left(1), Right(<function2>), Left(2))
scala> for (a <- elements) yield a match {
| case Right(f) => f(1,2)
| case Left(x) => x
| }
res1: List[Int] = List(1, 3, 2)
这里的限制是,如果你的List可以有两种以上的类型,它会变得笨拙。但与以前的解决方案不同,它有效地避免了强制Scala成为动态类型语言。
答案 1 :(得分:0)
如果您可以将a
打包到Option
,那么这将有效:
scala> val a:Option[Any] = Some(add)
a: Option[Any] = Some(<function2>)
scala> a match { case o:Some[operation] => println ("found"); case _ => }
found