“使用/尝试资源”的简单 Scala 模式(自动资源管理)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25634455/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simple Scala pattern for "using/try-with-resources" (Automatic Resource Management)
提问by clay
C# has usingwith the IDisposableinterface. Java 7+ has identical functionality with tryand the AutoCloseableinterface. Scala lets you choose your own implementation to this issue.
C#有using带IDisposable接口。Java 7+ 具有与try和AutoCloseable接口相同的功能。Scala 允许您针对此问题选择自己的实现。
scala-arm seems to be the popular choice, and is maintained by one of the Typesafe employees. However, it seems very complicated for such a simple behavior. To clarify, the usage instructions are simple, but understanding how all that code is working internally is rather complex.
scala-arm 似乎是流行的选择,由 Typesafe 的一名员工维护。然而,对于这样一个简单的行为来说,似乎非常复杂。澄清一下,使用说明很简单,但了解所有代码在内部如何工作却相当复杂。
I just wrote the following super simple ARM solution:
我刚刚写了以下超级简单的ARM解决方案:
object SimpleARM {
def apply[T, Q](c: T {def close(): Unit})(f: (T) => Q): Q = {
try {
f(c)
} finally {
c.close()
}
}
}
- Is there any benefit to something like simple-arm? It seems all the extra complexity should deliver extra benefit.
- Normally, it is highly preferable to use a public, open source, library that is supported by others for general purpose behavior over using custom code.
- Can anyone recommend any improvements?
- Are there any limitations to this simple approach?
- 像 simple-arm 这样的东西有什么好处吗?似乎所有额外的复杂性都应该带来额外的好处。
- 通常,与使用自定义代码相比,使用其他人支持的公共、开源库进行通用行为是非常可取的。
- 任何人都可以推荐任何改进吗?
- 这种简单的方法有什么限制吗?
采纳答案by clay
Here is my newer simple, understand at a glance, Scala ARM. This fully supports every use case I can think of including multiple resources and yield values. This uses a very simple for comprehension usage syntax:
下面是我较新的简单,一目了然,Scala ARM。这完全支持我能想到的每个用例,包括多个资源和产量值。这使用了一个非常简单的理解用法语法:
class AutoCloseableWrapper[A <: AutoCloseable](protected val c: A) {
def map[B](f: (A) => B): B = {
try {
f(c)
} finally {
c.close()
}
}
def foreach(f: (A) => Unit): Unit = map(f)
// Not a proper flatMap.
def flatMap[B](f: (A) => B): B = map(f)
// Hack :)
def withFilter(f: (A) => Boolean) = this
}
object Arm {
def apply[A <: AutoCloseable](c: A) = new AutoCloseableWrapper(c)
}
Here's demo use:
这是演示使用:
class DemoCloseable(val s: String) extends AutoCloseable {
var closed = false
println(s"DemoCloseable create ${s}")
override def close(): Unit = {
println(s"DemoCloseable close ${s} previously closed=${closed}")
closed = true
}
}
object DemoCloseable {
def unapply(dc: DemoCloseable): Option[(String)] = Some(dc.s)
}
object Demo {
def main(args: Array[String]): Unit = {
for (v <- Arm(new DemoCloseable("abc"))) {
println(s"Using closeable ${v.s}")
}
for (a <- Arm(new DemoCloseable("a123"));
b <- Arm(new DemoCloseable("b123"));
c <- Arm(new DemoCloseable("c123"))) {
println(s"Using multiple resources for comprehension. a.s=${a.s}. b.s=${b.s}. c.s=${c.s}")
}
val yieldInt = for (v <- Arm(new DemoCloseable("abc"))) yield 123
println(s"yieldInt = $yieldInt")
val yieldString = for (DemoCloseable(s) <- Arm(new DemoCloseable("abc")); c <- s) yield c
println(s"yieldString = $yieldString")
println("done")
}
}
回答by cchantep
Your approach with a single simple loan pattern is working fine as long as you don't need to work with several resources, all needing to be managed. That's allowed with scala-arm monadic approach.
只要您不需要使用多个资源,所有资源都需要进行管理,那么您使用单个简单贷款模式的方法就可以正常工作。Scala-arm monadic 方法允许这样做。
import resource.managed
managed(openResA).and(managed(openResB)) acquireFor { (a, b) => ??? }
val res = for {
a <- managed(openResA)
b <- managed(openResB)
c <- managed(openResC)
} yield (a, b, c)
res acquireAndGet {
case (a, b, c) => ???
}
Main functions to know in scala-arm is resource.managedand .acquired{For,AndGet}, not really complex btw.
Scala-arm 中要知道的主要功能是resource.managedand .acquired{For,AndGet},顺便说一句,并不是很复杂。
回答by david.perez
This is the code I use:
这是我使用的代码:
def use[A <: { def close(): Unit }, B](resource: A)(code: A ? B): B =
try
code(resource)
finally
resource.close()
Unlike Java try-with-resources, the resource doesn't need to implement AutoCloseable. Only a close()method is needed.
It only supports one resource.
与 Java try-with-resources 不同,资源不需要实现AutoCloseable。只close()需要一种方法。它只支持一种资源。
Here is an example use with an InputStream:
这是一个使用 的示例InputStream:
val path = Paths get "/etc/myfile"
use(Files.newInputStream(path)) { inputStream ?
val firstByte = inputStream.read()
....
}
回答by Peter Ertl
this one works for me really well:
这个对我来说非常有效:
implicit class ManagedCloseable[C <: AutoCloseable](resource: C) {
def apply[T](block: (C) => T): T = {
try {
block(resource)
} finally {
resource.close()
}
}
using it for example in this Apache Cassandra client code:
例如在这个 Apache Cassandra 客户端代码中使用它:
val metadata = Cluster.builder().addContactPoint("vader").withPort(1234).build() { cluster =>
cluster.getMetadata
}
or even shorter:
甚至更短:
val metadata = Cluster.builder().addContactPoint("sedev01").withPort(9999).build()(_.getMetadata)
回答by Arioch 'The
http://illegalexception.schlichtherle.de/2012/07/19/try-with-resources-for-scala/
http://illegalexception.schlichtherle.de/2012/07/19/try-with-resources-for-scala/
Another implementation, probably more clean from "follow Java specifications" viewpoint, but also fails to support multiple resources
另一种实现,从“遵循 Java 规范”的角度来看可能更干净,但也无法支持多种资源
回答by Johnny
An improvement I can recommend to the approach you suggested, which is:
我可以对您建议的方法进行改进,即:
def autoClose[A <: AutoCloseable, B](resource: A)(code: A ? B): B = {
try
code(resource)
finally
resource.close()
}
Is to use:
是使用:
def autoClose[A <: AutoCloseable, B](resource: A)(code: A ? B): Try[B] = {
val tryResult = Try {code(resource)}
resource.close()
tryResult
}
IMHO having the tryResult which is an Try[B], will allow you an easier control flow later.
恕我直言, tryResult 是一个Try[B], 将使您以后更容易控制流程。
回答by ChoppyTheLumberHyman
Choppy's Lazy TryClose monad might be what you are looking for (disclosure: I'm the author). It is very similar to Scala's Try but automatically closes resources automatically.
Choppy 的 Lazy TryClose monad 可能是您正在寻找的(披露:我是作者)。它与 Scala 的 Try 非常相似,但会自动关闭资源。
val ds = new JdbcDataSource()
val output = for {
conn <- TryClose(ds.getConnection())
ps <- TryClose(conn.prepareStatement("select * from MyTable"))
rs <- TryClose.wrap(ps.executeQuery())
} yield wrap(extractResult(rs))
// Note that Nothing will actually be done until 'resolve' is called
output.resolve match {
case Success(result) => // Do something
case Failure(e) => // Handle Stuff
}
See here for more info: https://github.com/choppythelumberHyman/tryclose
请参阅此处了解更多信息:https: //github.com/choppythelumberHyman/tryclose

