这个答案是 0__ 和 Nicolas Rinaudo 提供的部分答案的综合。
概括:
Scala 编译器做出了许多方便的(但也高度交织在一起的)假设。
- Scala 将
extends (A => B)
其视为extends Function1[A, B]
( ScalaDoc for Function1[+T1, -R] )的同义词
apply(x: A): B
必须提供Function1 继承的抽象方法的具体实现;def apply(x: A): B = cache.getOrElseUpdate(x, f(x))
- Scala 假设代码块的隐含
match
以= Memo {
- Scala将第
{}
3项开始之间的内容作为参数传递给Memo案例类构造函数
- Scala 假定
{}
在第 3 项中开始的隐含类型 asPartialFunction[Int, BigInt]
和编译器使用“匹配”代码块作为 PartialFunction 方法的覆盖apply()
,然后为 PartialFunction 方法提供额外的覆盖isDefinedAt()
。
细节:
定义案例类 Memo 的第一个代码块可以写得更详细:
case class Memo[A,B](f: A => B) extends Function1[A, B] { //replaced (A => B) with what it's translated to mean by the Scala compiler
private val cache = mutable.Map.empty[A, B]
def apply(x: A): B = cache.getOrElseUpdate(x, f(x)) //concrete implementation of unimplemented method defined in parent class, Function1
}
定义 val fibanocci 的第二个代码块可以写得更冗长,如下所示:
lazy val fibonacci: Memo[Int, BigInt] = {
Memo.apply(
new PartialFunction[Int, BigInt] {
override def apply(x: Int): BigInt = {
x match {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
}
override def isDefinedAt(x: Int): Boolean = true
}
)
}
必须添加lazy
到第二个代码块的 val 以处理行中的自引用问题case n => fibonacci(n-1) + fibonacci(n-2)
。
最后,斐波那契的一个示例用法是:
val x:BigInt = fibonacci(20) //returns 6765 (almost instantly)