1

看起来FirstSecond是一样的,但是为什么呢?

第一的

val iter = List(1, 2, 3, 4, 5).iterator
val first = iter.collect(new PartialFunction[Int, Int]{
  def apply(i: Int) = i
  def isDefinedAt(i: Int) = i > 0 && i < 3
})
first.foreach((println(_)))

第二

val iter2 = List(1, 2, 3, 4, 5).iterator
val second = iter2.collect {
  case i:Int if i > 0 && i < 3 => i
}
second.foreach((println(_)))

是不是因为 Scala 编译器会自动转换 { case i:Int if i > 0 && i < 3 => i }First的实现形式with generate isDefinedAtfrom if i > 0 && i < 3part?

另外,case i:Int if i > 0 && i < 3 => i如果我是正确的,是 Case 类模式匹配。但是,在scala/src/library/scala/PartialFunction.scala中,没有 Case 类定义PartialFunction

trait PartialFunction[-A, +B] extends (A => B)

那么为什么这个案例类模式匹配有效呢?

我想 Scala 编译器智能地做了很多隐式工作,但它让我无法理解正在发生的事情以及如何编写 Scala 代码。

如果有很好的参考资料,而不是语言或编译器规范,以了解 Scala 代码语法和 Scala 编写代码的方式,请提出建议。

4

3 回答 3

2

是的,编译器将第二个版本转换为 a PartialFunction[Int,Int](因为这是collect需要的)。

这里没有case class匹配,甚至在类型上也没有匹配,因为值必须是Int(因此不需要第二版本中的类型声明)。

风格指南提供了很多关于如何编写 Scala 的提示。

于 2019-11-16T12:25:10.093 回答
2

是不是因为 Scala 编译器会自动将 { case i:Int if i > 0 && i < 3 => i } 转换为 First 的实现形式,并从 **if i > 0 && i < 3 ** 部分生成 isDefinedAt?

是的,确切的翻译在Pattern Matching Anonymous Functions中给出。会在这里

new PartialFunction[Int, Int]{
  def apply(x: Int) = x match {
    case i:Int if i > 0 && i < 3 => i
  }
  def isDefinedAt(x: Int) = x match {
    case i:Int if i > 0 && i < 3 => true
    case _ => false
  } 
}

请注意与您的第一个示例的区别apply!当为 false时,您仍然可以调用它。isDefined

此外,如果我是正确的,case i:Int if i > 0 && i < 3 => i 是 Case 类模式匹配

如果有的话,情况正好相反;以这种方式调用 case 类是因为它们可以进行模式匹配,并且模式匹配case在 Scala 中使用关键字。

于 2019-11-16T12:25:48.187 回答
2

对于你的例子

object Main {
  def f = (1 to 5).collect { case i if i > 0 && i < 3 => i }
}

编译器生成的部分函数定义applyOrElse是因为它比天真的习语更有效:

if (pf.isDefinedAt(x)) pf.apply(x) else ???

显示该实现,类似于规范中描述的内容:

$ scalac -Vprint:typer pf.scala
[[syntax trees at end of                     typer]] // pf.scala
package <empty> {
  object Main extends scala.AnyRef {
    def <init>(): Main.type = {
      Main.super.<init>();
      ()
    };
    def f: IndexedSeq[Int] = scala.Predef.intWrapper(1).to(5).collect[Int](({
      @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Int,Int] with java.io.Serializable {
        def <init>(): <$anon: Int => Int> = {
          $anonfun.super.<init>();
          ()
        };
        final override def applyOrElse[A1 <: Int, B1 >: Int](x1: A1, default: A1 => B1): B1 = ((x1.asInstanceOf[Int]: Int): Int @unchecked) match {
          case (i @ _) if i.>(0).&&(i.<(3)) => i
          case (defaultCase$ @ _) => default.apply(x1)
        };
        final def isDefinedAt(x1: Int): Boolean = ((x1.asInstanceOf[Int]: Int): Int @unchecked) match {
          case (i @ _) if i.>(0).&&(i.<(3)) => true
          case (defaultCase$ @ _) => false
        }
      };
      new $anonfun()
    }: PartialFunction[Int,Int]))
  }
}

在哪里AbstractPartialFunction定义

def apply(x: T1): R = applyOrElse(x, PartialFunction.empty)

这是要使用的更改的外部链接applyOrElse。改进后的PartialFunction可以追溯到 2012 年。可能该功能的文档或广告不足。一些信息可以通过扩展Scaladoc 来获得PartialFunction。出于某种原因,该链接显示orElse,因此您实际上必须向后滚动applyOrElse。似乎文档很难。

于 2019-11-17T03:14:30.660 回答