在一堆具有类型E [String,A](其中A是多种类型)的Eithers上进行匹配后,我想将左边的任何字符串累积到列表中。
(a, b, c, d, e) match {
case (Right(a), Right(b), Right(c), Right(d), Right(e)) => {
"All good, use a, b, c, d, and e!"
}
case anythingElse => {
val strings = accLefts(anythingElse)
doSomethingWithStrings(strings)
}
}
如果我尝试.productIterator.toList
元组,我最终得到List [Any]。如果我单独处理每个失败的案例(权利和左派的组合),我最终会得到一个指数的案例陈述。
如何在那里获得一个列表[[String,Any]],以传递给我的accLefts电话?或者我应该做一些不同于匹配的事情?
答案 0 :(得分:5)
正好 Scalaz中ValidationNEL
(基本上是一个强化的Either
)旨在支持的事物。例如,假设我们使用Scalaz 7进行以下设置:
import scalaz._, Scalaz._
case class Person(first: String, last: String, initial: Char, age: Int)
val first = "John".successNel[String]
val last = "Doe".successNel[String]
val badLast = "Empty last name".failureNel[String]
val initial = 'H'.successNel[String]
val badInitial = "Non-alphabetic MI".failureNel[Char]
val age = 45.successNel[String]
val badAge = "Negative age provided".failureNel[Int]
请注意,此处Nel
代表非空列表,而"John".successNel[String]
或多或少等同于Right("John"): Either[List[String], String]
等。
现在我们可以写下以下内容:
scala> println((first |@| last |@| initial |@| age)(Person.apply))
Success(Person(John,Doe,H,45))
或者:
scala> println((first |@| badLast |@| initial |@| badAge)(Person.apply))
Failure(NonEmptyList(Empty last name, Negative age provided))
或者:
scala> println((first |@| badLast |@| badInitial |@| badAge)(Person.apply))
Failure(NonEmptyList(Empty last name, Non-alphabetic MI, Negative age provided))
任何错误都会累积在ValidationNEL
的左侧。参见例如我的回答here了解更多详情。
答案 1 :(得分:3)
也许嵌套模式匹配?
case anythingElse => {
val strings = anythingElse
.productIterator
.collect { case Left(str: String) => str }
.toList
doSomethingWithStrings(strings)
}
请注意,str: String
此处用于指导类型推断,因此字符串的类型List[String]
不是List[Any]
答案 2 :(得分:0)
我可能会创建一组实用程序函数,如
def fromTuple2[A, That](t: Tuple2[A,A])(implicit bf : CanBuildFrom[Nothing, A, That]): That =
(bf.apply() += (t._1, t._2)).result();
您需要的所有 n 元组。虽然它是很多锅炉板代码,但它只是一次性工作。然后你可以做以下事情:
val e1: Either[String,Int] = Right(3);
val e2: Either[String,String] = Left("3");
val test: List[Either[String,Any]] = fromTuple2(e1, e2);
或许更好,我们可以使用浓缩隐式方法,如
implicit def fromTuple2Impl[A](t: Tuple2[A,A]) = new {
def asCollection[That](implicit bf : CanBuildFrom[Nothing, A, That]): That =
(bf.apply() += (t._1, t._2)).result();
}
只写
val test: List[Either[String,Any]] = (e1, e2).asCollection;
编辑:我们甚至可以将元组丰富为Traversable
s,这样就可以获得toList
,折叠等所有方法:
implicit def fromTuple2Impl3[A](t: Tuple2[A,A]) = new Traversable[A] {
def asCollection[That](implicit bf : CanBuildFrom[Nothing, A, That]): That =
(bf.apply() += (t._1, t._2)).result();
override def foreach[U](f: (A) => U): Unit = {
f(t._1); f(t._2);
}
}
通过更多工作,我们可以进一步实施IndexedSeq
。