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)
虽然这个解决方案可能会起作用,但它非常尴尬.我怎样才能改进它?
为了完整起见,我在此处添加了一段处理所需值的代码。然而,这是否比原版更好还有待商榷。如果您想处理所有值并收集转换结果,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)