在Scala中转换多个可选值

Ral*_*lph 5 scala type-conversion optional

我正在编写一个函数,它接收几个可选String值并将每个值转换为a Int或a Boolean,然后将转换后的值传递给Unit函数以进行进一步处理.如果任何转换失败,整个函数将失败并显示错误.如果所有转换都成功,则该函数应处理转换后的值并返回成功.

这是我写的函数(从实际中简化):

f(x: Option[String], y: Option[String], z: Option[String]): Result = {
  val convertX = x.map(value => Try(value.toInt))
  val convertY = y.map(value => Try(value.toBoolean))
  val convertZ = z.map(value => Try(value.toBoolean))

  val failuresExist =
    List(convertX, convertY, convertZ).flatten.exists(_.isFailure)

  if (failuresExist) BadRequest("Cannot convert input")
  else {
    convertX.foreach {
      case Success(value) => processX(value)
      case _ =>
    }

    convertY.foreach {
      case Success(value) => processY(value)
      case _ =>
    }

    convertZ.foreach {
      case Success(value) => processZ(value)
      case _ =>
    }

    Ok()
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然这个解决方案可能会起作用,但它非常尴尬.我怎样才能改进它?

Mak*_*tis 0

为了完整起见,我在此处添加了一段处理所需值的代码。然而,这是否比原版更好还有待商榷。如果您想处理所有值并收集转换结果,scalaz Validator可能是更好的选择。

import scala.util.Try

val x = Some("12")
val y = Some("false")
val z = Some("hello")

def process(v: Boolean) = println(s"got a $v")
def processx(v: Int) = println(s"got a number $v")

// Abstract the conversion to the appropriate mapping
def mapper[A, B](v: Option[String])(mapping: String => A)(func: Try[A] => B) = for {
    cx <- v.map(vv => Try(mapping(vv)))
  } yield func(cx)

def f(x: Option[String], y: Option[String], z: Option[String]) = {
  //partially apply the function here. We will use that method twice.
  def cx[B] = mapper[Int, B](x)(_.toInt) _
  def cy[B] = mapper[Boolean, B](y)(_.toBoolean) _
  def cz[B] = mapper[Boolean, B](z)(_.toBoolean) _

  //if one of the values is a failure then return the BadRequest, 
  // else process each value and return ok
  (for {
    vx <- cx(_.isFailure)
    vy <- cy(_.isFailure)
    vz <- cz(_.isFailure)
    if vx || vy || vz
  } yield {
    "BadRequest Cannot convert input"
  }) getOrElse {
    cx(_.map(processx))
    cy(_.map(process))
    cz(_.map(process))
    "OK"
  }

}
f(x,y,z)
Run Code Online (Sandbox Code Playgroud)

在需要“短路”行为的情况下,以下代码将起作用。

import scala.util.Try

val x = Some("12")
val y = Some("false")
val z = Some("hello")


def process(v: Boolean) = println(s"got a $v")
def processx(v: Int) = println(s"got a number $v")

def f(x: Option[String], y: Option[String], z: Option[String]) =
  (for {
     cx <- x.map(v => Try(v.toInt))
     cy <- y.map(v => Try(v.toBoolean))
     cz <- z.map(v => Try(v.toBoolean))
  } yield {
     val lst = List(cx, cy, cz)
      lst.exists(_.isFailure) match {
       case true => "BadRequest Cannot convert input"
       case _ =>
          cx.map(processx)
          cy.map(process)
          cz.map(process)
          "OK"
      }
  }) getOrElse "Bad Request: missing values"

f(x,y,z) 
Run Code Online (Sandbox Code Playgroud)