19

C# にusingIDisposableインターフェイスがあります。Java 7+ には、tryおよびAutoCloseableインターフェースと同じ機能があります。Scala では、この問題に対する独自の実装を選択できます。

scala-arm が一般的な選択肢のようで、Typesafe の従業員の 1 人によって保守されています。しかし、このような単純な動作は非常に複雑に思えます。明確にするために、使用手順は簡単ですが、すべてのコードが内部でどのように機能するかを理解するのはかなり複雑です。

次の非常に単純な ARM ソリューションを作成しました。

object SimpleARM {
  def apply[T, Q](c: T {def close(): Unit})(f: (T) => Q): Q = {
    try {
      f(c)
    } finally {
      c.close()
    }
  }
}
  • シンプルアームのようなものに何か利点はありますか? 余分な複雑さはすべて、余分な利益をもたらすはずです。
  • 通常、カスタム コードを使用するよりも、汎用的な動作のために他のユーザーによってサポートされている公開されたオープン ソース ライブラリを使用することを強くお勧めします。
  • 誰でも改善を推奨できますか?
  • この単純なアプローチに制限はありますか?
4

9 に答える 9

10

単一の単純なローン パターンを使用したアプローチは、すべてを管理する必要がある複数のリソースを操作する必要がない限り、うまく機能します。これは、scala-arm モナド アプローチで許可されます。

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}、それほど複雑ではありません。

于 2014-09-03T00:52:12.563 に答える
6

これが私の新しいシンプルで一目でわかる 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")
  }
}
于 2016-03-28T00:26:48.020 に答える
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()が必要です。1 つのリソースのみをサポートします。

を使用した例を次に示しますInputStream

val path = Paths get "/etc/myfile"
use(Files.newInputStream(path)) { inputStream ⇒
    val firstByte = inputStream.read()
    ....
}
于 2016-12-29T11:57:40.490 に答える