33

「using」関数を次のように定義しました。

def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A =
  try { f(closeable) } finally { closeable.close() }

私はそれを次のように使用できます:

using(new PrintWriter("sample.txt")){ out =>
  out.println("hellow world!")
}

今、「using」関数を定義して任意の数のパラメーターを取り、それらに個別にアクセスできるようにする方法に興味があります。

using(new BufferedReader(new FileReader("in.txt")), new PrintWriter("out.txt")){ (in, out) =>
  out.println(in.readLIne)
}
4

9 に答える 9

13

誰かがすでにこれを行っています — それはScala ARMと呼ばれています。

readme から:

import resource._
for(input <- managed(new FileInputStream("test.txt")) {
  // Code that uses the input as a FileInputStream
}
于 2011-10-13T03:07:23.290 に答える
6

私はこれについて考えてきましたが、これに対処する別の方法があるのではないかと考えました。これは、「任意の数」のパラメーターをサポートすることに関する私の見解です(タプルが提供するものによって制限されます):

object UsingTest {

  type Closeable = {def close():Unit }

  final class CloseAfter[A<:Product](val x: A) {
    def closeAfter[B](block: A=>B): B = {
      try {
        block(x);
      } finally {
        for (i <- 0 until x.productArity) {
          x.productElement(i) match { 
            case c:Closeable => println("closing " + c); c.close()
            case _ => 
          }
        }
      }
    }
  }

  implicit def any2CloseAfter[A<:Product](x: A): CloseAfter[A] = 
    new CloseAfter(x)

  def main(args:Array[String]): Unit = {
    import java.io._

    (new BufferedReader(new FileReader("in.txt")), 
     new PrintWriter("out.txt"),
     new PrintWriter("sample.txt")) closeAfter {case (in, out, other) => 
      out.println(in.readLine) 
      other.println("hello world!")
    }
  }
}

ライブラリに 22 個のタプル/製品クラスが記述されているという事実を再利用していると思います... この構文は、ネストされたものを使用するusingよりも明確ではないと思います(しゃれは意図されていません) が、興味深いパズルでした。

于 2010-03-08T08:33:00.020 に答える
2

これは、java.io.Closeable である任意のアイテムの自動リソース管理ブロックとして理解のために scala を使用できるようにする例ですが、close メソッドを使用して任意のオブジェクトに対して機能するように簡単に拡張できます。

この使用法は using ステートメントにかなり近いようで、1 つのブロックで必要な数のリソースを簡単に定義できます。

object ResourceTest{
  import CloseableResource._
  import java.io._

  def test(){
    for( input <- new BufferedReader(new FileReader("/tmp/input.txt")); output <- new FileWriter("/tmp/output.txt") ){
      output.write(input.readLine)
    }
  }
}

class CloseableResource[T](resource: =>T,onClose: T=>Unit){
  def foreach(f: T=>Unit){
    val r = resource
    try{
      f(r)
    }
    finally{
      try{
        onClose(r)
      }
      catch{
        case e =>
          println("error closing resource")
          e.printStackTrace
      }
    }
  }
}

object CloseableResource{
  implicit def javaCloseableToCloseableResource[T <: java.io.Closeable](resource:T):CloseableResource[T] = new CloseableResource[T](resource,{_.close})
}
于 2010-03-10T20:23:58.503 に答える
2

残念ながら、標準の Scala では、任意の型を持つ任意の長さのパラメーター リストはサポートされていません。

言語をいくつか変更することで、このようなことができるかもしれません (変数パラメーター リストを HList として渡すことができるようにするためです。必要なものの約 1/3 については、こちらを参照してください)。

現時点で最善の方法は、Tuple や Function と同じことを行うことです: 必要な数の N に対して usingN を実装します。

もちろん、2 つは簡単です。

def using2[A, B <: {def close(): Unit}, C <: { def close(): Unit}](closeB: B, closeC: C)(f: (B,C) => A): A = {
  try { f(closeB,closeC) } finally { closeB.close(); closeC.close() }
}

さらに必要な場合は、ソース コードを生成するものを作成する価値があります。

于 2010-03-07T14:04:35.370 に答える