What Automatic Resource Management alternatives exist for Scala?

后端 未结 9 1390
半阙折子戏
半阙折子戏 2020-12-02 03:57

I have seen many examples of ARM (automatic resource management) on the web for Scala. It seems to be a rite-of-passage to write one, though most look pretty much like one a

9条回答
  •  长情又很酷
    2020-12-02 04:20

    Chris Hansen's blog entry 'ARM Blocks in Scala: Revisited' from 3/26/09 talks about about slide 21 of Martin Odersky's FOSDEM presentation. This next block is taken straight from slide 21 (with permission):

    def using[T <: { def close() }]
        (resource: T)
        (block: T => Unit) 
    {
      try {
        block(resource)
      } finally {
        if (resource != null) resource.close()
      }
    }
    

    --end quote--

    Then we can call like this:

    using(new BufferedReader(new FileReader("file"))) { r =>
      var count = 0
      while (r.readLine != null) count += 1
      println(count)
    }
    

    What are the drawbacks of this approach? That pattern would seem to address 95% of where I would need automatic resource management...

    Edit: added code snippet


    Edit2: extending the design pattern - taking inspiration from python with statement and addressing:

    • statements to run before the block
    • re-throwing exception depending on the managed resource
    • handling two resources with one single using statement
    • resource-specific handling by providing an implicit conversion and a Managed class

    This is with Scala 2.8.

    trait Managed[T] {
      def onEnter(): T
      def onExit(t:Throwable = null): Unit
      def attempt(block: => Unit): Unit = {
        try { block } finally {}
      }
    }
    
    def using[T <: Any](managed: Managed[T])(block: T => Unit) {
      val resource = managed.onEnter()
      var exception = false
      try { block(resource) } catch  {
        case t:Throwable => exception = true; managed.onExit(t)
      } finally {
        if (!exception) managed.onExit()
      }
    }
    
    def using[T <: Any, U <: Any]
        (managed1: Managed[T], managed2: Managed[U])
        (block: T => U => Unit) {
      using[T](managed1) { r =>
        using[U](managed2) { s => block(r)(s) }
      }
    }
    
    class ManagedOS(out:OutputStream) extends Managed[OutputStream] {
      def onEnter(): OutputStream = out
      def onExit(t:Throwable = null): Unit = {
        attempt(out.close())
        if (t != null) throw t
      }
    }
    class ManagedIS(in:InputStream) extends Managed[InputStream] {
      def onEnter(): InputStream = in
      def onExit(t:Throwable = null): Unit = {
        attempt(in.close())
        if (t != null) throw t
      }
    }
    
    implicit def os2managed(out:OutputStream): Managed[OutputStream] = {
      return new ManagedOS(out)
    }
    implicit def is2managed(in:InputStream): Managed[InputStream] = {
      return new ManagedIS(in)
    }
    
    def main(args:Array[String]): Unit = {
      using(new FileInputStream("foo.txt"), new FileOutputStream("bar.txt")) { 
        in => out =>
        Iterator continually { in.read() } takeWhile( _ != -1) foreach { 
          out.write(_) 
        }
      }
    }
    

提交回复
热议问题