4

我之前问过这个问题:将 PartialFunction 与常规函数结合起来

然后意识到,我实际上并没有问对。所以,这里又进行了一次尝试。

如果我这样做:

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

它不编译: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 }

问题是有什么区别?在这两种情况下,参数的类型是相同的:PartialFunction[Int, String]. 传入的值实际上是相同的。为什么一个案例有效,而另一个案例无效?

4

3 回答 3

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情况下将其充分键入。

于 2016-07-13T20:49:59.247 回答
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")
}
于 2016-09-03T13:19:40.137 回答
0

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

val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar : (Int => String) = foo orElse { case x => x.toString }
于 2016-07-13T19:33:55.817 回答