C#的using
接口为IDisposable
。 Java 7+具有与try
和AutoCloseable
接口相同的功能。 Scala允许您为此问题选择自己的实现。
我刚刚编写了以下超级简单的ARM解决方案:
object SimpleARM {
def apply[T, Q](c: T {def close(): Unit})(f: (T) => Q): Q = {
try {
f(c)
} finally {
c.close()
}
}
}
答案 0 :(得分:11)
只要您不需要使用多个资源,只需要管理一个简单的贷款模式,您的方法就可以正常运行。 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) => ???
}
scala-arm中要知道的主要功能是resource.managed
和.acquired{For,AndGet}
,而不是真正复杂的btw。
答案 1 :(得分:4)
这是我的新手简单,一目了然,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)
}
以下演示用法:
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")
}
}
答案 2 :(得分:3)
这是我使用的代码:
def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B =
try
code(resource)
finally
resource.close()
与Java try-with-resources不同,资源不需要实现AutoCloseable。只需要close()
方法。
它只支持一种资源。
以下是使用InputStream
的示例:
val path = Paths get "/etc/myfile"
use(Files.newInputStream(path)) { inputStream ⇒
val firstByte = inputStream.read()
....
}
答案 3 :(得分:1)
http://illegalexception.schlichtherle.de/2012/07/19/try-with-resources-for-scala/
另一个实现,从“遵循Java规范”的角度来看可能更干净,但也无法支持多个资源
答案 4 :(得分:1)
这个对我很有用:
none
在此Apache Cassandra客户端代码中使用它:
implicit class ManagedCloseable[C <: AutoCloseable](resource: C) {
def apply[T](block: (C) => T): T = {
try {
block(resource)
} finally {
resource.close()
}
}
甚至更短:
val metadata = Cluster.builder().addContactPoint("vader").withPort(1234).build() { cluster =>
cluster.getMetadata
}
答案 5 :(得分:1)
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
}
有关详细信息,请参阅此处:https://github.com/choppythelumberjack/tryclose
答案 6 :(得分:0)
我可以向您建议的方法推荐一项改进,即:
def autoClose[A <: AutoCloseable, B](resource: A)(code: A ⇒ B): B = {
try
code(resource)
finally
resource.close()
}
是使用:
def autoClose[A <: AutoCloseable, B](resource: A)(code: A ⇒ B): Try[B] = {
val tryResult = Try {code(resource)}
resource.close()
tryResult
}
IMHO拥有Try[B]
的tryResult,可以让你以后更容易控制流程。
答案 7 :(得分:0)
我会这样做:
def tryFinally[A, B](acquire: Try[A])(use: A => B)(release: A => Unit): Try[B] =
for {
resource <- acquire
r = Try(use(resource)).fold(
e => { release(resource); throw e },
b => { release(resource); b }
)
} yield r
您可以对其调用 .get
并使其返回 B
。