Using a variable in finally block

前端 未结 4 1139
忘掉有多难
忘掉有多难 2021-01-22 10:29

Here is code in Scala:

def write() = {
    try {
      val out = new PrintWriter(new BufferedWriter(new FileWriter(fileName, true)))
      out.println(\"123\")
          


        
4条回答
  •  Happy的楠姐
    2021-01-22 11:33

    The loan pattern is more usual for this use case, but since anything goes on Stack Overflow, you can construct the expression you're looking for with Try.

    Try deserves more exposure as a handy tool.

    scala> import util._
    import util._
    
    scala> import io._
    import io._
    

    Try to open the file --

    scala> def f =
         | Try (Source.fromFile("foo.text")) map { in =>
    

    then do something with it, packaging the result in a tuple with the i/o source -- note that when you do a value definition in a for-comprehension, this is what it does --

         |   (in, Try(in.getLines.mkString("/")))
         | } flatMap {
    

    then close the source and yield the result of the computation --

         |   case (in, res) =>
         |     in.close()
         |     res
         | }
    f: scala.util.Try[String]
    

    Uncommented:

    scala> def f =
         | Try (Source.fromFile("foo.text")) map { in =>
         |   (in, Try(in.getLines.mkString("/")))
         | } flatMap {
         |   case (in, res) =>
         |     in.close()
         |     res
         | }
    f: scala.util.Try[String]
    
    scala> f
    res1: scala.util.Try[String] = Failure(java.io.FileNotFoundException: foo.text (No such file or directory))
    

    Create the test file with some classic humour text, then try again:

    scala> f
    res2: scala.util.Try[String] = Success(Now is the time/for all good dogs/to lie.)
    

    You can sugarcoat it as a for-comprehension, though observe the extra flatten, since you get a map instead of flatMap from the yield:

    scala> def g = (for {
         |   in <- Try (Source.fromFile("foo.text"))
         |   res = Try(in.getLines.mkString("/"))
         | } yield {
         |   in.close()
         |   res
         | }).flatten
    g: scala.util.Try[String]
    
    scala> g
    res2: scala.util.Try[String] = Success(Now is the time/for all good dogs/to lie.)
    

    What if we want to fail if the close fails?

    I don't want to type in all that stuff into the REPL again!

    scala> :hi             // :history
    [snip]
    2490  def g = (for {
    2491    in <- Try (Source.fromFile("foo.text"))
    2492    res = Try(in.getLines.mkString("/"))
    2493  } yield {
    2494    in.close()
    2495    res
    2496  }).flatten
    2497  :hi
    
    scala> :edit 2490+7    // or just :edit 2490-
    +import util._
    +import io._
    +def g = (for {
    +  in <- Try (Source.fromFile("foo.text"))
    +  res = Try(in.getLines.mkString("/"))
    +} yield {
    +  val ok = Try(in.close())
    +  res transform (s => ok map (_ => s), new Failure(_))
    +}).flatten
    +
    import util._
    import io._
    g: scala.util.Try[String]
    

    The transform says that if the computation succeeded, convert that success to failure if the result of the close, ok, is a failure; and on a failed computation, keep that failure, though some people prefer to add up their failures.

    Don't you know try/catch is so 1990s. (droll does not mean troll.)

提交回复
热议问题