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

ear*_*las 1 scala

给定以下类型和实例:

type operation = (Int, Int) => Int
def add: operation = _ + _
Run Code Online (Sandbox Code Playgroud)

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

for (a <- elements) a match {
  case o: operation => // do stuff
}
Run Code Online (Sandbox Code Playgroud)

有没有办法实现这种基于函数的打字,同时在case语句中易于擦除?

注意,这与此线程类似.

Jam*_*Iry 7

处理类型擦除的一种简单方法是创建一个unparamaterized类.它并不完美,但它确实有效.使它成为一个扩展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)
Run Code Online (Sandbox Code Playgroud)

限制是你必须在失去类型之前进行"盒装"操作,而不是之后.此外,每个具体的函数类型最终会有一个类.

另一个可以说是更好的解决方案是不丢失类型信息.使用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)
Run Code Online (Sandbox Code Playgroud)

这里的限制是,如果你的List可以拥有超过2种类型,它会变得笨拙.但与以前的解决方案不同,它有效地避免了强制Scala成为动态类型语言.