Scala有没有类似于Go语言的defer的功能?

huangapple go评论165阅读模式
英文:

Does Scala have an equivalent to golangs defer?

问题

Scala有没有类似于Go语言的defer的功能?

来自:
http://golang.org/doc/effective_go.html#defer
>Go的defer语句会安排一个函数调用(被延迟的函数)在执行defer的函数返回之前立即运行。这是一种不寻常但有效的处理情况的方式,比如无论函数通过哪个路径返回,都必须释放资源的情况。典型的例子包括解锁互斥锁或关闭文件。

英文:

Does Scala have an equivelent to golangs defer?

from:
http://golang.org/doc/effective_go.html#defer
>Go's defer statement schedules a function call (the deferred function) to be run immediately before the function executing the defer returns. It's an unusual but effective way to deal with situations such as resources that must be released regardless of which path a function takes to return. The canonical examples are unlocking a mutex or closing a file.

答案1

得分: 9

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
}

在这个示例中,Deferrable是一个包装函数,它调用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 does not offer defer by design, however you can create it yourself by wrapping
your function in another function, passing an object which keeps track of functions to call.

Example:

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
}

In this example, Deferable would be the wrapping function which calls context and
returns it contents, giving it an object which tracks defer calls.

You can use this construct like this:

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

The output would be:

before return
dtest: 6
dtest: 3
3

I'm aware that this can be solved differently but it is really just an example that
Scala supports the concept of defer without too much fuss.

答案2

得分: 6

我可以给你提供一个翻译版本,如下所示:

我无法想到一个特定于Scala的方法,但这个等效的方式是不是这样(虽然不够优雅):

try {
    // 做一些事情
} finally {
    // "defer"
}

希望对你有帮助!如果你还有其他问题,请随时提问。

英文:

I can't think of a Scala specific way, but wouldn't this be equivalent (though not as pretty):

try {
    // Do stuff   
} finally {
    // "defer"
}

答案3

得分: 2

No. Go语言之所以有这个结构,正是因为它不支持异常,并且没有try...finally语法。

就个人而言,我认为这会引发维护上的困扰;对defer的调用可以埋藏在函数的任何地方。即使负责任的程序员将defer放在需要清理的地方旁边,我认为它比finally块不够清晰,至于它让混乱的程序员做什么...至少finally块将所有的清理工作放在一个地方。

defer与Scala的惯用法相反。Scala提供了控制程序流程的单子方式,而defer的魔法对此没有任何贡献。单子相对于try...finally提供了功能上的改进,它让你可以:

  • 定义自己的错误处理流程
  • 函数式地操作已定义的流程
  • 将函数预期的错误作为其签名的一部分

defer在这里没有任何用处。

英文:

No. Go has this construct precisely because it doesn't support exceptions and has no try...finally syntax.

Personally, I think it invites a maintenance nightmare; calls to defer can be buried anywhere in a function. Even where responsible coders put the defers right beside the thing to be cleaned up, I think it's less clear than a finally block and as for what it lets the messy coders do... at least finally blocks put all the clean-up in one place.

defer is the opposite of idiomatic Scala. Scala offers monadic ways to control program flow and defer magic does not contribute at all. Monads offer a functional improvement over try...finally which let you

  • Define your own error handling flow
  • Manipulate defined flows functionally
  • Make a function's anticipated errors part of its signature

defer has no place in this.

huangapple
  • 本文由 发表于 2013年9月17日 16:45:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/18845210.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定