【发布时间】:2013-09-17 08:45:46
【问题描述】:
Scala 是否具有与 golangs defer 等效的功能?
来自: http://golang.org/doc/effective_go.html#defer
Go 的 defer 语句安排函数调用(延迟函数)在执行 defer 的函数返回之前立即运行。这是一种不寻常但有效的方式来处理诸如无论函数采用哪条路径返回都必须释放资源的情况。典型示例是解锁互斥锁或关闭文件。
【问题讨论】:
Scala 是否具有与 golangs defer 等效的功能?
来自: http://golang.org/doc/effective_go.html#defer
Go 的 defer 语句安排函数调用(延迟函数)在执行 defer 的函数返回之前立即运行。这是一种不寻常但有效的方式来处理诸如无论函数采用哪条路径返回都必须释放资源的情况。典型示例是解锁互斥锁或关闭文件。
【问题讨论】:
Scala 没有通过设计提供defer,但是您可以通过包装自己创建它
您的函数在另一个函数中,传递一个跟踪要调用的函数的对象。
例子:
class DeferTracker() {
class LazyVal[A](val value:() => A)
private var l = List[LazyVal[Any]]()
def apply(f: => Any) = { l = new LazyVal(() => f) :: l }
def makeCalls() = l.foreach { x => x.value() }
}
def Deferrable[A](context: DeferTracker => A) = {
val dt = new DeferTracker()
val res = context(dt)
dt.makeCalls
res
}
在本例中,Deferable 将是调用 context 和
返回它的内容,给它一个跟踪defer调用的对象。
你可以像这样使用这个结构:
def dtest(x:Int) = println("dtest: " + x)
def someFunction(x:Int):Int = Deferrable { defer =>
defer(dtest(x))
println("before return")
defer(dtest(2*x))
x * 3
}
println(someFunction(3))
输出将是:
before return
dtest: 6
dtest: 3
3
我知道这可以通过不同的方式解决,但这只是一个例子 Scala 支持 defer 的概念,不用大惊小怪。
【讨论】:
我想不出 Scala 特定的方式,但这不就是等效的吗(虽然不那么漂亮):
try {
// Do stuff
} finally {
// "defer"
}
【讨论】:
没有。 Go 有这个结构正是因为它不支持异常并且没有try...finally 语法。
就我个人而言,我认为这会引发一场维护噩梦;对 defer 的调用可以隐藏在函数的任何地方。即使负责任的编码人员将延迟放在要清理的东西旁边,我认为它也没有finally 块那么清楚,至于它让凌乱的编码器做什么......至少finally 块把所有的干净-在一个地方。
defer 与惯用的 Scala 相反。 Scala 提供了控制程序流的单子方法,而defer 魔法根本没有贡献。 Monad 提供了对 try...finally 的功能改进,让您
defer 在此没有位置。
【讨论】:
defer func() {whatever();was();in();finally();block()},我看不出有什么缺点。您可以争辩说RAII 或来自C# 和python 的等效using 不那么混乱,但是finally?这是完全相同的野兽。
defer 语句对 me 来说是一大优势。我不喜欢一直向下滚动到 finally 块来查看作者是否真的关闭了文件(或其他)。
using example here 很容易,所以你可以只做 using(resource) { res => res.doSomething(); res.doSomethingElse(); } 或者,如果它是一个简单的一次性操作,那么 val result = using(resource) { _.read(); },当然有适当的身份...... :)
defer 几乎相反。不同的语义和更清晰的结构。如果你想添加你自己关于using 的答案,我很乐意投赞成票,同时评论它与defer 有多么不同;)