使用Scala中的[String,B]优雅地累积错误的问题

时间:2016-10-17 04:31:26

标签: scala

我试图在这里解析一个csv行,每个字段可以是不同的类型。为了处理错误累积,我使用的是[String,B],其中String是错误消息,B是值。这里的问题是B可以是不同的类型,Option [Int],String,Array [String],导致我的Map类型(String,Either [String,java.io.Serializable])有效地使地图无法使用。有没有办法(我肯定有)更优雅地积累错误,同时重用这些值来填充对象的属性?

override def parseCsv(implicit fields: Map[String, String]): Either[String, User] = {

  val parsedValues = Map(Headers.Id -> getFieldAsString(Headers.Id),
                    Headers.FirstName -> getFieldAsString(Headers.FirstName),
                    Headers.LastName -> getFieldAsString(Headers.LastName),
                    Headers.Email -> getFieldAsString(Headers.Email),
                    Headers.TimeZone -> getFieldAsString(Headers.TimeZone),
                    Headers.Region -> getOption(Headers.Region),
                    Headers.Phone -> getOption(Headers.Phone),
                    Headers.ProfileImage -> getFieldAsString(Headers.ProfileImage),
                    Headers.Roles -> getFieldAsArray(Headers.Roles))
  val errors = parsedValues.collect { case (key, Left(errors)) => errors }
  if (!errors.isEmpty) Left(errors.mkString(", "))
  else {
    val user = new User
    user.id = getFieldAsString(Headers.Id).right.get
    user.firstName = getFieldAsString(Headers.FirstName).right.get
    user.lastName = getFieldAsString(Headers.LastName).right.get
    user.email = getFieldAsString(Headers.Email).right.get
    user.timeZone = getFieldAsString(Headers.TimeZone).right.get
    user.phoneNumber = (for {
                          region <- getOption(Headers.Region).right.get
                          phone <- getOption(Headers.Phone).right.get
                          _ = validatePhoneNumber(phone, region)
                        } yield {
                          new PhoneNumber(region, phone)
                        }).orNull
    user.profileImageUrl = getFieldAsString(Headers.ProfileImage).right.get
    user.roles = getFieldAsArray(Headers.Roles).right.get
    Right(user)
  }
}

1 个答案:

答案 0 :(得分:1)

为所有类型的case classes创建B。这些案例类必须扩展一些共同特征。在填充用户对象时,只需模式匹配并检索值。

sealed trait Result {
  val paramName: String
}

case class OptionInt(override val paramName: String, value: Option[Int]) extends Result

case class ArrayString(override val paramName: String, value: Array[String]) extends Result

case class StringValue(override val paramName: String, value: String) extends Result

现在最终的类型就像Either[String, Result]

解析整个文件后创建List[Result]

如果您期望ageOption[Int]firstNameString,请执行此操作

list.foreach { result =>
    result match {
      case Option("age", value) => userId.age = value.getOrElse(defaultAge)
      case StringValue("firstName", value) => userId.firstName = value
      case StringValue("email", value) => userId.email = value
      case _ => //do nothing
    }
}