摘要:差异代表一个结果的两个可能性,一个是,一个是代表可选择的值,一个是代表有值,一个是值为空常用于结果可能为的情况运算的结果有两种情况,一个是运行正常,即,一个是运行出错,抛出异常,即,其中里面包含的是异常的信息共同点三者都存在两种可能性的值都
差异
Either
代表一个结果的两个可能性,一个是 Right ,一个是 Left
Option
代表可选择的值,一个是 Some(代表有值),一个是 None (值为空);常用于结果可能为 null 的情况;
Try
运算的结果有两种情况,一个是运行正常,即 Success ,一个是运行出错,抛出异常 ,即 Failure ,其中 Failure 里面包含的是异常的信息;
共同点
三者都存在两种可能性的值;都可以在结果之上进行 map 、 flatMap 等操作;
Either
Right 和 Left 是继承自 Either 的两个 case 类;
//Left final case class Left[+A, +B](@deprecatedName("a, "2.12.0") value: A) extends Either[A, B] //Right final case class Right[+A, +B](@deprecatedName("b, "2.12.0") value: B) extends Either[A, B]
Eihter 代表一个结果的两个可能性,一个是 Right ,一个是 Left ;
import scala.io.StdIn._ val in = readLine("Type Either a string or an Int: ") val result: Either[String,Int] = try Right(in.toInt) catch { case e: NumberFormatException => Left(in) } result match { case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}" case Left(x) => s"You passed me the String: $x" }
Either 是偏向 Right 值的,在 Either 使用 map 、flatMap 等操作时,只有 Either 的结果是 Right 时,才会触发操作;习惯性地将Left 值代表不好的结果(失败的结果),Right 代表好的结果(成功的结果);
def doubled(i: Int) = i * 2 Right(42).map(doubled) // Right(84) Left(42).map(doubled) // Left(42)
由于Either 定义了 flatMap 和 map ,所以可以对 Either 使用 for comprehensions;
val right1 = Right(1) : Right[Double, Int] //确定right1的类型 val right2 = Right(2) val right3 = Right(3) val left23 = Left(23.0) : Left[Double, Int] //确定left23的类型 val left42 = Left(42.0) for { x <- right1 y <- right2 z <- right3 } yield x + y + z // Right(6) for { x <- right1 y <- right2 z <- left23 } yield x + y + z // Left(23.0) for { x <- right1 y <- left23 z <- right2 } yield x + y + z // Left(23.0)
但是不支持使用守卫表达式
for { i <- right1 if i > 0 } yield i // error: value withFilter is not a member of Right[Double,Int]
同样,下面也是不支持的
for (x: Int <- right1) yield x // error: value withFilter is not a member of Right[Double,Int]
由于 for comprehensions 使用 map 和 flatMap ,所以必须要推导参数的类型,并且该类型必须是 Either ;特别的地方在于,由于Either 是偏向Right 的,所以是对于Either的值为Left必须要指定其类型,否则,该位置的默认类型为Nothing;
for { x <- left23 y <- right1 z <- left42 // type at this position: Either[Double, Nothing] } yield x + y + z // ^ // error: ambiguous reference to overloaded definition, // both method + in class Int of type (x: Char)Int // and method + in class Int of type (x: Byte)Int // match argument types (Nothing) for (x <- right2 ; y <- left23) yield x + y // Left(23.0) for (x <- right2 ; y <- left42) yield x + y // error for { x <- right1 y <- left42 // type at this position: Either[Double, Nothing] z <- left23 } yield x + y + z // Left(42.0), but unexpectedly a `Either[Double,String]`
Option
Some 和 None 是继承自 Option 的两个 case 类;
//Some final case class Some[+A](@deprecatedName("x, "2.12.0") value: A) extends Option[A] //None case object None extends Option[Nothing]
对Option 的习惯用法是把它当作集合或者monad ,通过map 、flatMap 、filter 和 foreach :
//方式一 val name: Option[String] = request getParameter "name" val upper = name map { _.trim } filter { _.length != 0 } map { _.toUpperCase } println(upper getOrElse "") //方式一等价于方式二 val upper = for { name <- request getParameter "name" //由于For表达式的作用,如何此处返回None,那么整个表达式将返回None trimmed <- Some(name.trim) upper <- Some(trimmed.toUpperCase) if trimmed.length != 0 } yield upper println(upper getOrElse "")
另外一个习惯用法是(不太推荐)通过模式匹配:
val nameMaybe = request getParameter "name" nameMaybe match { case Some(name) => println(name.trim.toUppercase) case None => println("No name value") }
Try
Failure 和 Success 是继承自 Try 的两个 case 类;
//Failure final case class Failure[+T](exception: Throwable) extends Try[T] //Success final case class Success[+T](value: T) extends Try[T]
Try 常用于那些存在异常的地方,通过Try 不用确定地对可能出现的异常进行处理;
import scala.io.StdIn import scala.util.{Try, Success, Failure} def divide: Try[Int] = { val dividend = Try(StdIn.readLine("Enter an Int that you"d like to divide: ").toInt) val divisor = Try(StdIn.readLine("Enter an Int that you"d like to divide by: ").toInt) val problem = dividend.flatMap(x => divisor.map(y => x/y)) problem match { case Success(v) => println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v) Success(v) case Failure(e) => println("You must"ve divided by zero or entered something that"s not an Int. Try again!") println("Info from the exception: " + e.getMessage) divide } }
在上面的例子中,可以看出 Try 的一个重要的特性,就是Try 具有管道的功能 ,flatMap 和 map 将那些成功完成的操作的结果包装成Success ,将那些异常包装成 Failure ,而对于 recover 和 recoverWith 则是默认对 Failure 结果进行触发;
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/71147.html
摘要:复制代码报错信息如下错误错误解答执行命令安装依赖包。为了让读者理解问题,重现上述错误过程,命令如下复制代码1、Nginx安装过程报错错误一:软件依赖包未正确安装问题---PCRE依赖包没有安装 ./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the...
摘要:在深入理解中的变量上中我们看到的引入,使得可以很方便地在多线程环境中使用局部变量。特别需要注意的是,基类的并不会屏蔽派生类中的创建。到此,整个源码核心部分已经理解的差不多了,只剩下用来执行清除工作。 在 深入理解Python中的ThreadLocal变量(上) 中我们看到 ThreadLocal 的引入,使得可以很方便地在多线程环境中使用局部变量。如此美妙的功能到底是怎样实现的?如果你...
摘要:在中也可以看到执行记录,包括错误信息解读生命周期在任务开始之前即在初始化之后执行任何或实现之前创建一个记录记录开始事件的条目,此事件由触发,来向系统指出所有都可以使用。在加载完成所有的之后,任务执行并更新数据库中的执行结果和状态,最后退出。 起步:什么是 spring cloud task Spring Cloud Task makes it easy to create short ...
摘要:源码漫游二描述在一中其实已经把作为的框架中数据流相关跑了一遍。看上面两排公共方法这个方法的调用在整个源码中就两处,和。过程,这也是导致我们在源码运行中总是看见在有无函数分支,的时候总是能看见函数,然后就进入对组件。 Vue2 源码漫游(二) 描述: 在(一)中其实已经把Vue作为MVVM的框架中数据流相关跑了一遍。这一章我们先看mount这一步,这样Vue大的主线就基本跑通了。...
阅读 2260·2023-04-25 14:50
阅读 1234·2021-10-13 09:50
阅读 1866·2019-08-30 15:56
阅读 1839·2019-08-29 15:29
阅读 2886·2019-08-29 15:27
阅读 3548·2019-08-29 15:14
阅读 1192·2019-08-29 13:01
阅读 3299·2019-08-26 14:06