为什么 Scala PartialFunction 在不定义 isDefinedAt 的情况下工作?
Why Scala PartialFunction works without defining isDefinedAt?
看起来第一个和第二个是一样的,但是为什么呢?
第一个
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 的实现形式,从 if i > 0 && i < 3
部分生成 isDefinedAt
?
此外,case i:Int if i > 0 && i < 3 => i
是 Case class 模式匹配,如果我是正确的话。但是,在 scala/src/library/scala/PartialFunction.scala 中,PartialFunction
没有 Case class 定义。
trait PartialFunction[-A, +B] extends (A => B)
那为什么这种情况 class 模式匹配有效?
我想 Scala 编译器可以智能地完成大量隐式工作,但它让我无法理解正在发生的事情以及如何编写 Scala 代码。
如果有很好的参考,而不是语言或编译器规范,可以理解
Scala代码语法和Scala写代码的方式,请指教。
是的,编译器将第二个版本转换为 PartialFunction[Int,Int]
(因为 collect
就是这样)。
这里没有匹配case class
,甚至没有匹配类型,因为值必须是Int
(因此不需要第二个版本中的类型声明)。
style guide 给出了很多关于 Scala 典型编写方式的提示。
Is it because the Scala compiler automatically converts { case i:Int if i > 0 && i < 3 => i } into the implelentation form of First with generating isDefinedAt from **if i > 0 && i < 3 ** part?
是的,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
中的第一个示例的区别!当 isDefined
为 false 时,您 可以 仍然调用它。
Also, case i:Int if i > 0 && i < 3 => i is Case class pattern matching, if I am correct
如果说有什么不同的话,那就是反过来了; case 类 被这样调用是因为它们可以进行模式匹配,模式匹配在 Scala 中使用 case
关键字。
以你为例
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)
这里是an external link to a change to use applyOrElse
. The improved PartialFunction dates back to 2012. Probably the feature is under-documented or under-advertised. Some information is available by expanding the Scaladoc for PartialFunction
。出于某种原因,link 显示 orElse
,因此您实际上必须向后滚动才能找到 applyOrElse
。看来文档很难。
看起来第一个和第二个是一样的,但是为什么呢?
第一个
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 的实现形式,从 if i > 0 && i < 3
部分生成 isDefinedAt
?
此外,case i:Int if i > 0 && i < 3 => i
是 Case class 模式匹配,如果我是正确的话。但是,在 scala/src/library/scala/PartialFunction.scala 中,PartialFunction
没有 Case class 定义。
trait PartialFunction[-A, +B] extends (A => B)
那为什么这种情况 class 模式匹配有效?
我想 Scala 编译器可以智能地完成大量隐式工作,但它让我无法理解正在发生的事情以及如何编写 Scala 代码。
如果有很好的参考,而不是语言或编译器规范,可以理解 Scala代码语法和Scala写代码的方式,请指教。
是的,编译器将第二个版本转换为 PartialFunction[Int,Int]
(因为 collect
就是这样)。
这里没有匹配case class
,甚至没有匹配类型,因为值必须是Int
(因此不需要第二个版本中的类型声明)。
style guide 给出了很多关于 Scala 典型编写方式的提示。
Is it because the Scala compiler automatically converts { case i:Int if i > 0 && i < 3 => i } into the implelentation form of First with generating isDefinedAt from **if i > 0 && i < 3 ** part?
是的,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
中的第一个示例的区别!当 isDefined
为 false 时,您 可以 仍然调用它。
Also, case i:Int if i > 0 && i < 3 => i is Case class pattern matching, if I am correct
如果说有什么不同的话,那就是反过来了; case 类 被这样调用是因为它们可以进行模式匹配,模式匹配在 Scala 中使用 case
关键字。
以你为例
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)
这里是an external link to a change to use applyOrElse
. The improved PartialFunction dates back to 2012. Probably the feature is under-documented or under-advertised. Some information is available by expanding the Scaladoc for PartialFunction
。出于某种原因,link 显示 orElse
,因此您实际上必须向后滚动才能找到 applyOrElse
。看来文档很难。