Scala中与Python的`with`相对应的替代方案是什么?

3
在Python中,你可以使用with来避免使用try {} catch {} finally {}语句块(参见Python中的关键字“with”有什么用?)。我记得在Scala中看到过类似的替代方案,但现在找不到了。
它大致的语法如下:
def using[O](r: {def close()})(doit: () => O): O = try {
  doit()
} finally {
  r.close
}

using(myWriter){() => myWriter.println("something or another")}

它是内置在2.10中的吗,还是我需要一个单独的库来使用?


5
目前最广为人知的用于实现这一功能的库是https://github.com/jsuereth/scala-arm,而且据我所知,Scala未提供此功能。 - om-nom-nom
1个回答

6

几乎可以轻松制作自己的框架来覆盖几乎所有用例(这里使用2.10版):

implicit class TidyUpAnything[A](val a: A) extends AnyVal {
  def tidily[Z](g: A=>Any)(f: A=>Z) = try { f(a) } finally { g(a) }
}

如果您希望异常通过,请按原样使用:
scala> Option(null: String).tidily(println){_.get}   // Should print None
None
java.util.NoSuchElementException: None.get
    at scala.None$.get(Option.scala:313)
    ...

如果您想处理异常,请与scala.util.Try一起使用:

scala> import scala.util._
scala> Try( Option(null: String).tidily(println){ _.get } )
None
res1: scala.util.Try[String] = Failure(java.util.NoSuchElementException: None.get)

通常情况下,您会将 g 设置为类似于 _.close 的内容,但是您可以使用它执行任意资源清理。例如,在此处,每当我们完成时,我们会将计数器减少一次:
var i = 0
val a = Array(1,2)
a.tidily(_ => i -= 1){ _.foreach(_ => i += 1) }
scala> i
res2: Int = 1

我也想到了类似的解决方案,但我认为可能已经有现成的工具可以实现这个功能。Scala-arm似乎是一个很好的选择,可以避免自己重新造轮子。 - iwein
1
如果您需要更多的功能,scala-arm确实非常有吸引力。但仅仅为了这个目的,添加一个依赖项而不是三行代码似乎有些奇怪的冲动。 - Rex Kerr
点已经被接受。使用scala-arm得到的语法可能比使用TidyUpAnything得到的语法更好。我有些害怕为通用情况添加隐式。 - iwein
1
@iwein - 如果您喜欢没有隐式参数的一行代码,那么您完全可以使用def tidily[A,Z](resource: A)(tidy: A => Any)(act: A=>Z) = try { act(resource) } finally { tidy(resource) }。但是,我们同意scala-arm在某些情况下具有更好的语法。 - Rex Kerr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接