如何在 Scala 中地道地编写它?
How to write it idiomatically in Scala?
假设我有一个检查字符串的函数:
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String):Either[MyError, Unit] =
if (s == "a") Right(()) else Left(oops)
现在我想重用它并编写一个新函数来检查字符串列表的头部和 return 错误或列表尾部。
// should be validateHeadOfList but I don't want to change the name now
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs match {
case head::tail =>
validate(head).fold(err => Left(err), _ => Right(tail))
case _ => Left(oops)
}
这个功能有效,但看起来不够优雅。你会如何改进它?
假设您确实想要 return 单个错误或原始列表,那么以下方法将起作用。不过,我无法评论这是否是惯用的 Scala。
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String): Either[MyError, Unit] =
if (s == "a") ().asRight else oops.asLeft
final def validateList(list: List[String]): Either[MyError, List[String]] = {
@scala.annotation.tailrec
def loop(xs: List[String]): Either[MyError, List[String]] = {
xs match {
case head :: tail =>
validate(head) match {
case Left(error) => error.asLeft
case _ => loop(tail)
}
case _ => list.asRight
}
}
loop(list)
}
例如:
scala> validateList(List("a", "a", "a"))
res0: Either[MyError,List[String]] = Right(List(a, a, a))
scala> validateList(List("a", "b", "a"))
res1: Either[MyError,List[String]] = Left(MyError(oops))
你的实现对我来说看起来相当地道,但如果你正在寻找一个可能更简洁的替代方案 - 我认为这完全相同,并且(可以说)更简洁:
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs.headOption.map(validate).map(_.right.map(_ => xs.tail)).getOrElse(Left(oops))
假设我有一个检查字符串的函数:
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String):Either[MyError, Unit] =
if (s == "a") Right(()) else Left(oops)
现在我想重用它并编写一个新函数来检查字符串列表的头部和 return 错误或列表尾部。
// should be validateHeadOfList but I don't want to change the name now
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs match {
case head::tail =>
validate(head).fold(err => Left(err), _ => Right(tail))
case _ => Left(oops)
}
这个功能有效,但看起来不够优雅。你会如何改进它?
假设您确实想要 return 单个错误或原始列表,那么以下方法将起作用。不过,我无法评论这是否是惯用的 Scala。
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String): Either[MyError, Unit] =
if (s == "a") ().asRight else oops.asLeft
final def validateList(list: List[String]): Either[MyError, List[String]] = {
@scala.annotation.tailrec
def loop(xs: List[String]): Either[MyError, List[String]] = {
xs match {
case head :: tail =>
validate(head) match {
case Left(error) => error.asLeft
case _ => loop(tail)
}
case _ => list.asRight
}
}
loop(list)
}
例如:
scala> validateList(List("a", "a", "a"))
res0: Either[MyError,List[String]] = Right(List(a, a, a))
scala> validateList(List("a", "b", "a"))
res1: Either[MyError,List[String]] = Left(MyError(oops))
你的实现对我来说看起来相当地道,但如果你正在寻找一个可能更简洁的替代方案 - 我认为这完全相同,并且(可以说)更简洁:
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs.headOption.map(validate).map(_.right.map(_ => xs.tail)).getOrElse(Left(oops))