从源码层面理解 Either、Option 和 Try
差异
- Either
代表一个结果的两个可能性,一个是 Right
,一个是 Left
- Option
代表可选择的值,一个是 Some
(代表有值),一个是 None
(值为空);常用于结果可能为 null
的情况;
- Try
运算的结果有两种情况,一个是运行正常,即 Success
,一个是运行出错,抛出异常 ,即 Failure
,其中 Failure
里面包含的是异常的信息;
共同点
三者都存在两种可能性的值;都可以在结果之上进行 map
、 flatMap
等操作;
- Either
Right
和 Left
是继承自 Either
的两个 case
类;
//Leftfinal case class Left[+A, +B](@deprecatedName('a, "2.12.0") value: A) extends Either[A, B]//Rightfinal 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 * 2Right(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 <- right1y <- right2z <- right3} yield x + y + z // Right(6)for {x <- right1y <- right2z <- left23} yield x + y + z // Left(23.0)for {x <- right1y <- left23z <- right2} yield x + y + z // Left(23.0)
但是不支持使用守卫表达式
for {i <- right1if 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 <- left23y <- right1z <- 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 // errorfor {x <- right1y <- 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
类;
//Somefinal case class Some[+A](@deprecatedName('x, "2.12.0") value: A) extends Option[A]//Nonecase 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,那么整个表达式将返回Nonetrimmed <- Some(name.trim)upper <- Some(trimmed.toUpperCase) if trimmed.length != 0} yield upperprintln(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
类;
//Failurefinal case class Failure[+T](exception: Throwable) extends Try[T]//Successfinal case class Success[+T](value: T) extends Try[T]
Try
常用于那些存在异常的地方,通过Try
不用确定地对可能出现的异常进行处理;
import scala.io.StdInimport scala.util.{Try, Success, Failure}def divide: Try[Int] = {val dividend = Try(StdIn.readLine("Enter an Int that you'd like to divide:\n").toInt)val divisor = Try(StdIn.readLine("Enter an Int that you'd like to divide by:\n").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
结果进行触发;
从源码层面理解 Either、Option 和 Try相关推荐
- spring的事务隔离_再深一点:面试工作两不误,源码级理解Spring事务
原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...
- 再深一点:面试工作两不误,源码级理解Spring事务
原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...
- spring更新后 外层事务查不到_再深一点:面试工作两不误,源码级理解Spring事务...
原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...
- Spring原理学习系列之三:Spring AOP原理(从源码层面分析)-------上部
引言 本文是Spring原理分析的第三篇博文,主要阐述Spring AOP相关概念,同时从源码层面分析AOP实现原理.对于AOP原理的理解有利于加深对Spring框架的深入理解.同时我也希望可以探究S ...
- android 点击事件消费,Android View事件分发和消费源码简单理解
Android View事件分发和消费源码简单理解 前言: 开发过程中觉得View事件这块是特别烧脑的,看了好久,才自认为看明白.中间上网查了下singwhatiwanna粉丝的读书笔记,有种茅塞顿开 ...
- 结合源码深入理解Android Crash处理流程
应用程序crash在开发过程中还是很常见的,本文主要是从源码的角度去跟踪下Android对于crash的处理流程.App crash的全称:Application crash.而Crash又分为:na ...
- Android学习之Activity源码的理解(一)
一.Activity为Android系统中四大组件之一,是Android程序的呈现层,并通过界面与用户进行交互,因此理解Activity源码是有必要的. 二.之前我写过一篇文章:http://blog ...
- LruCache源码的理解
LruCache源码的理解 使用场景 在Android手机上加载图片,一般会用到三级缓存策略 内存的缓存策略,一般会用到LruCache来解决 内存用于缓存遇到的问题 1. 手机给每个应用分配的内存空 ...
- PointNetPointNet++源码ModelNetDataLoader理解
PointNet&PointNet++源码ModelNetDataLoader理解 源码:https://github.com/yanx27/Pointnet_Pointnet2_pytorc ...
- 从源码角度理解LinearLayout#onMeasure对child的measure调用次数
熟悉绘制流程的都知道,ViewGroup可以决定child的绘制时机以及调用次数. 今天我们就从LinearLayout开始学起,看一下它对子View的onMeasure调用次数具体是多少. 简单起见 ...
最新文章
- akaze特征匹配怎么去掉不合适的点_图像匹配几种常见算法与实践
- iOS保存model数据(自定义Model 可以存放到本地)
- linux oel7没有网络,rhel7/oel7上修改默认内核启动顺序的方法
- 8.分布式数据库HBase第4部分
- Codeforces 685C Optimal Point (二分、不同类型距离的相互转换)
- python 自定义模块的发布和安装
- mysql grant教程_MySQL如何使用授权命令grant
- python beautifulsoup4 table tr_python BeautifulSoup解析表
- opencv rect画旋转矩形_在opencv c中绘制旋转的矩形
- deep deepfm wide 区别_个性化推荐如何满足用户口味?微信看一看的技术这样做
- Java常用类(三):FileUtils类
- 如何批量设置 Word 文档的打开密码?
- win10 企业版2016长期服务激活教程
- 移动Web第七天(响应式网页:媒体查询、BootStrap)
- 关于cv.waitKey
- 如何将多个excel表格合并成一个_如何将多个PDF文档合并为一个
- [算法竞赛入门经典] UVA 12174 - Shuffle
- 双精度移位指令SHLD,SHRD
- 【basler】Chapter3:basler相机出现斜黑条纹
- A. New Year and Hurry
热门文章
- 手把手教你从零开始腾讯云服务器部署
- 程序人生:程序员如何和老板谈升职加薪
- 数论学习笔记之解线性方程 a*x + b*y = gcd(a,b)
- sqlserver Month()函数取日期不足两位的加 0
- 图解数据分析(4) | 核心步骤1 - 业务认知与数据初探(数据科学家入门·完结)
- 在 FlashGot 中调用 Axel 下载
- 【考研数学】五. 二重积分
- 一个优秀的系统分析员应该具备的三个素质
- 电脑电源问题,导致攒机电脑无法开机
- 【NBA之路】启蒙—to—詹皇—to—保罗乔治