匿名PartialFunction语法

时间:2016-07-13 18:48:19

标签: scala partialfunction partial-functions

我之前问了这个问题:Combine a PartialFunction with a regular function

然后意识到,我实际上并没有问过它。 所以,这是另一种尝试。

如果我这样做:

 val foo = PartialFunction[Int, String] { case 1 => "foo" }
 val bar = foo orElse { case x => x.toString }

它无法编译:{{1​​}}

但这很好用:

error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: PartialFunction[?,?]

问题是有什么区别?在两种情况下,参数的类型都相同: val x: Seq[String] = List(1,2,3).collect { case x => x.toString } 。传入的值实际上是相同的。为什么一个案件有效,而另一个案件无效?

3 个答案:

答案 0 :(得分:0)

您需要指定bar的类型,因为编译器无法推断它。这编译:

val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar : (Int => String) = foo orElse { case x => x.toString }

答案 1 :(得分:0)

List(1,2,3).collect{case x => x.toString}的情况下,编译器能够根据List的输入方式推断出部分函数的输入类型。

final override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[List[A], B, That])

根据类型参数,编译器可以推断出您正在传递正确类型的部分函数。这就是List(1,2,3).collect{case x:String => x.toString}无法编译,List(1,2,3).collect{case x:Int => x.toString; case x: String => x.toString}的原因。

由于List是协变的,编译器能够推断出部分函数{case x => x.toString}Int上的部分函数。您会注意到List(1,2,3).collect{case x => x.length}无法编译,因为编译器推断您正在IntInt的子类上运行。

另请注意,{case x => x.toString}只是语法糖。如果我们执行类似下面的操作,那么您的示例将按预期工作

val f = new PartialFunction[Int, String](){
  override def isDefinedAt(x: Int): Boolean = true
  override def apply(v1: Int): String = v1.toString
}

val foo = PartialFunction[Int, String] { case 1 => "foo" }

val bar = foo orElse f //This compiles fine.

List(1,2,3).collect{f} // This works as well.

因此,从我的观点来看,唯一合乎逻辑的答案是,能够为PartialFunction生成{case x => x.toString}实例的语法糖在编译时没有足够的信息才能将其充分输入为PartialFunction[Int, String]案例中的orElse

答案 2 :(得分:0)

您可以使用库Extractor.scala

import com.thoughtworks.Extractor._

// Define a PartialFunction
val pf: PartialFunction[Int, String] = {
  case 1 => "matched by PartialFunction"
}

// Define an optional function
val f: Int => Option[String] = { i =>
  if (i == 2) {
    Some("matched by optional function")
  } else {
    None
  }
}

// Convert an optional function to a PartialFunction
val pf2: PartialFunction[Int, String] = f.unlift

util.Random.nextInt(4) match {
  case pf.extract(m) => // Convert a PartialFunction to a pattern
    println(m)
  case f.extract(m) => // Convert an optional function to a pattern
    println(m)
  case pf2.extract(m) => // Convert a PartialFunction to a pattern
    throw new AssertionError("This case should never occur because it has the same condition as `f.extract`.")
  case _ =>
    println("Not matched")
}