捕获并执行延续
var count: (Unit => Unit) = null
var fileName = "myfile.txt"
var contents = ""
reset {
while(contents == "") {
try {
contents = scala.io.Source.fromFile(fileName, "UTF-8").mkString
} catch {case _ => }
shift {k: (Unit => Unit) =>
cont = k
}
}
}
“运算当中挖个洞”
要理解到底一个延续捕获了什么,我们可以把shift块想象成一个位于reset块中的“洞”。当你执行延续时,你可以将一个值传到这个洞中,运算继续,就好像shift本就是那个值一样。
reset和shift的控制流转
reset/shift的控制流转悠双重职责:一方面定义延续函数,另一方面又捕获延续函数。
当你调用reset时,它的代码体便开始执行。当执行遇到shift时,shift的代码体被调用,传入延续函数作为参数。当shift完成后,执行立即跳转到包含延续的reset块的末尾。
var cont : (Unit => Unit) = null
reset {
print("Before shift")
shift {
k: (Unit => Unit) => {
cont = k
println("Inside shift") //跳转到reset末尾
}
}
println("After shift")
}
println("After reset")
cont()
CPS注解
定义:延续传递风格:(CPS)
def tryRead(): Unit @cps[Unit] = {
while (contents == "") {
try{
contents = scala.io.Source.fromFile(filename, "UTF-8").mkString
}catch {case _ => }
shift {
k:(Unit => Unit) =>
cont = k
}
}
}
将递归访问转化为迭代
import scala.util.continuations._
import java.io_
object PrintFiles extends APP {
var cont : (Unit => Unit) =null
def processDirectory(dir: File): Unit @cps[Unit] ={
var files = dir.listFiles
var i = 0
while(i < files.length) {
val f = files(i)
i += 1
if (f.isDirectory)
processDirectory(f)
else {
shift {
k: (Unit => Unit) => {cont = k}
}//
println(f)
}
}
}
reset {
processDirectory(new File("/"))
}
for (i <- 1 to 100) cont()
}