Scala中的函数类型定义和类型擦除

时间:2011-02-23 03:43:07

标签: scala

给出以下类型和实例:

type operation = (Int, Int) => Int
def add: operation = _ + _

如果我尝试匹配case语句中的操作,Scala会因为类型擦除而抱怨未经检查的输入:

for (a <- elements) a match {
  case o: operation => // do stuff
}

在case语句中是否有一种方法可以实现这种基于函数的输入,同时具有易擦除性?

注意,这类似于this thread

2 个答案:

答案 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