跟连乐一起学Scala-定界延续

捕获并执行延续

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()
}

你可能感兴趣的:(scala)