san*_*4ka 4 functional-programming scala
假设我们有3个方法都返回一个 Option
import scala.util.Try
def divideSafe(d: Int): Option[Int] = Try(42 / d).toOption
def sqrtSafe(x: Double): Option[Double] = if(!math.sqrt(x).isNaN) Some(math.sqrt(x)) else None
def convertSafe(s: String): Option[Int] = Try(s.toInt).toOption
Run Code Online (Sandbox Code Playgroud)
现在,我想在条件成立时将它们链接起来。就我而言,如果定义了前一个方法的结果,则应转到下一个方法。并且只要条件为假,就停止操作并返回默认值。
我可以使用嵌套的if-else语句获得所需的结果:
def superSafe(d: Int, x: Double, s: String): Unit = {
if (divideSafe(d).isDefined) {
println(divideSafe(d).get.toString)
if (sqrtSafe(x).isDefined) {
println(sqrtSafe(x).toString)
if (convertSafe(s).isDefined) {
println(convertSafe(s).get.toString)
} else {
println("Converting failed")
}
} else {
println("Sqrt failed")
}
} else {
println("Dividing failed")
}
}
Run Code Online (Sandbox Code Playgroud)
因此:
superSafe(1, -1, "5")将打印42而Sqrt失败
superSafe(0, 4, "cat")将打印除法失败
superSafe(42, 4, 1)将打印1,2,1
但是,我想避免嵌套的if-else语句,并且我对Scala中是否存在解决此类问题的功能性方法很感兴趣。
我想要类似orElse声明的内容,但反之亦然。
所需的功能可以这样使用:
divideSafe(42) ifThen("Dividing failed") sqrtSafe(-4) ifThen("Sqrt failed") convertSafe("cat") ifThen("Converting failed")
Run Code Online (Sandbox Code Playgroud)
您使用Option的不是最适合您的用例。我相信Either在您的示例中会更好,因为它可以保存有关failure(Left)或成功(Right)的信息。如果重写了要使用的函数,Either则它可能类似于:
def divideSafe(d: Int): Either[String, Int] = Try(42 / d).toOption.toRight("Divide failed")
def sqrtSafe(x: Double): Either[String, Double] = math.sqrt(x) match {
case s if s.isNaN => Left("Sqrt failed") //you can use pattern matching to calculate square just once
case s => Right(s)
}
def convertSafe(s: String): Either[String, Int] = Try(s.toInt).toOption.toRight("Converting failed")
Run Code Online (Sandbox Code Playgroud)
然后可以for comprehension在您的superSafe方法中使用:
def superSafe(d: Int, x: Double, s: String): Unit = {
val r: Either[String, (Int, Double, Int)] = for { //for-comprehension shortcircuits
r1 <- divideSafe(d) //if divideSafe fails it whole comprehension will return Left(Divide failed)
r2 <- sqrtSafe(x) //if it succeds it will go further
r3 <- convertSafe(s)
} yield (r1,r2,r3)
r match {
case Right((r1,r2,r3)) => { //you could move it inside yield, I splitted it for clarity
println(r1)
println(r2)
println(r3)
}
case Left(e) => println(e)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
133 次 |
| 最近记录: |