这是我之前question的后续内容。假设我有以下功能:
type Result[A] = Either[String, A] // left is an error message
def f1(a: A): Result[B] = ...
def f2(b: B): Result[C] = ...
def f3(c: C): Result[D] = ...
def f(a: A): Result[D] = for {
b <- f1(a).right
c <- f2(b).right
d <- f3(c).right
} yield d;
假设我还想将更多信息添加到错误消息中。
def f(a: A): Result[D] = for {
b <- { val r = f1(a); r.left.map(_ + s"failed with $a"); r.right }
c <- { val r = f2(b); r.left.map(_ + s"failed with $a and $b"); r.right }
d <- { val r = f3(c); r.left.map(_ + s"failed with $a, $b, and $c"); r.right }
} yield d;
代码看起来很难看。你会如何建议改进代码?
答案 0 :(得分:1)
代码看起来很难看,因为你正在重复自己。
改为编写方法!或者是一种扩展方法。其中之一,也许是:
implicit class StringEitherCanAdd[A](private val e: Either[String, A]) extends AnyVal {
def info(s: String): Either[String, A] = e.left.map(_ + s)
def failed(a: Any*): Either[String, A] =
if (a.length == 0) e
else if (a.length == 1) e.left.map(_ + s"failed with ${a(0)}")
else if (a.length == 2) e.left.map(_ + s"failed with ${a(0)} and ${a(1)}")
else e.left.map(_ + s"failed with ${a.init.mkString(", ")}, and ${a.last}")
}
现在你只是
f1(a).info(s"failed with $a").right
f2(b).failed(a,b).right