我有许多操作资源的函数对,例如:
def loadFile(name: String): Option[String]
def writeFile(name: String, data: String): ???
当前实现了loadFile 以使用Option Some / None返回结果String但是 writeFile 呢?
与 loadFile 一样,如果 writeFile 失败,我希望它返回包含在一个不错的Try或Option中的响应,而不是抛出异常或返回null,Boolean,或响应代码。
有哪些推荐的最佳做法?
def writeFile(name: String, data: String): Try(Unit)
或
def writeFile(name: String, data: String): Option(Unit)
只是测试成功标志?
最好的scala-thonic方法是什么?
答案 0 :(得分:4)
这里的其他答案与Try[Unit]
几乎相同,但需要更多的样板。这很简单(字面意思是在函数定义中添加3个字母):
def writeFile(name: String, data: String): Try[Unit] = Try {
// do write operation that may throw an exception
}
Try
的巨大优势在于它是一个monad,因此您可以map
和flatMap
(以及其他内容)组成多个Try
{1}}轻松地成为一个人。假设您需要同时执行其中的3个操作,并返回Unit
或第一个Exception
。
val result: Try[Unit] = for {
a <- writeFile(name1, data1)
b <- writeFile(name2, data2)
c <- writeFile(name3, data3)
} yield ()
您可以匹配结果:
result match {
case Success(_) => println("Success!")
case Failure(t) => println(s"Failure! {t.getMessage}")
}
您还有一些其他强大的组合函数,如API docs中所示。
和您还可以编写更通用的方法来重试失败,如this post中的最后一段代码所示。
答案 1 :(得分:1)
过去,我采用了一种看起来像这样的方法。
trait Result
case object Success extends Result
case class Error(errorReason: String) extends Result
def writeFile(name: String): Result
它与模式匹配范例非常适用。
def writeFileWithRetry(name: String)(numRetries: Int = 2): Result = {
writeFile(name) match {
case e: Error =>
LOG.errorLog(s"Could not write $name: ${e.errorReason}")
if (numRetries <= 0) e else writeFileWithRetry(name)(numRetries - 1)
case r => r
}
}
答案 2 :(得分:0)
def writeFile(name: String, data: String): Either[Exception, Unit] = try {
doWrite(name, data)
Right(())
} catch {
case ex => Left(ex)
}
writeFile("foo", "bar") match {
case Left(ex) => println("Failed with exception: " + ex)
case _ => println("Success!")
}