Как функционально обрабатывать ввод-вывод

#scala

#scala

Вопрос:

У меня есть следующий код, я не хочу использовать var SysProc есть ли функциональный способ сделать это?

    var proc: SysProc = null
    try {
      proc = SysProc(scalaTestCommand).run(ProcessLogger(out.append, out.append))
      forkProcess(proc, Settings.scalaTestTimeout)
    } catch {
      case e: TimeoutException =>
        val msg = "Timeout when running ScalaTestn"   out.toString()
        logError(msg)
        proc.destroy()
        sys.error(msg)
      case e: Throwable =>
        val msg = "Error occurred while running the ScalaTest commandn"   e.toString   "n"   out.toString()
        logError(msg)
        proc.destroy()
        throw e
    } finally {
      println(out.toString)
      if (proc != null) {
        println("Exit process: "   proc.exitValue())
      }
    }
  

Ответ №1:

Технически, если ваш SysProc конструктор выдает ошибку во время построения, var не будет установлен, так что вы уже можете сделать что-то вроде этого:

 try {
  val proc = SysProc(scalaTestCommand).run(ProcessLogger(out.append, out.append))
  try {
    forkProcess(proc, Settings.scalaTestTimeout)
  } finally {
    proc.destroy()
    println("Exit process: "   proc.exitValue())
  }
} catch {
  case e: TimeoutException =>
    val msg = "Timeout when running ScalaTestn"   out.toString()
    logError(msg)
    sys.error(msg)
  case e: Throwable =>
    val msg = "Error occurred while running the ScalaTest commandn"   e.toString   "n"   out.toString()
    logError(msg)
    throw e
}
  

и это уже код без переменных.

Если вы хотите быть еще более функциональным, вы можете рассмотреть что-то вроде cats.effect.Resource и cats.effect.IO :

 Resource {
  // how to acquire resource
  IO(SysProc(scalaTestCommand).run(ProcessLogger(out.append, out.append)))
} { proc =>
  // how release resource when it is not needed
  // - no matter if it was used successfuly or not
  IO {
    proc.destroy()
    println("Exit process: "   proc.exitValue())
  }
} // defines resource
 .use(forkProcess(_, Settings.scalaTestTimeout)) // create-use-release resource
 .handleErrorWith {
    case e: TimeoutException =>
      val msg = s"Timeout when running ScalaTestn$out"
      IO(logError(msg)) >> IO(sys.error(msg))
  case e: Throwable =>
      val msg = s"Error occurred while running the ScalaTest commandn$en$out"
      IO(logError(msg)) >> IO.raiseError(e)
  } // handle errors if happened
  .unsafeRunSync // run computation (in this case synchronously)