引用透明:表达式可以被引用的值替代,表达式不依赖上下文
类型安全:在编译时检测到类型异常,而不是在运行时检测到类型异常
b. 处理异常的其他方式异常检测:
1. scala高阶函数高度泛化,传入参数(函数或数值)的类型需要通过推断获得,类型推断必需根据上下文依赖中的显示标记类型推断得出,换句话讲,scala需要高度信任显示标记类型,因此,不能感知由参数类型推断错误以外的特定异常;
2. java强制要求对异常进行处理或抛出,每次编译都会检查上下文依赖中抛出的异常,因此在函数式编程时传入函数如果存在异常,则必需进行相应处理或抛出,会对签名模板进行改变(签名模板包含:名称、类型、次序、异常),会对代码模板进行改变(代码模板包含各种if-else逻辑,用于处理各种可能抛出的常见异常)
2. Option类型 a. 定义Option类型
- 预前处理:改变参数列表:增加默认参数,在代码中出现以外情况时,使用默认值继续运行(关键词:默认值,目的:防止运行报错)
- 预后处理:if-else判断:通过if-else判断,找到代码中可能出现的意外情况,处理或抛出异常(关键词:异常,目的:停止运行)
- 预前延迟处理:Option数据类型,定义默认值与正常值
- 预后延迟处理:Either数据类型,定义异常与正常值
定义顺序类型的基本过程:
- 定义基本类型;
- 定义用于表示0的对象;
- 定义用于表示1-N的类型
// 从trait开始,定义原始类型Option,
sealed trait Option[+A]{
// 为演示函数提升,需要有map函数,this代表任意一个继承了Option的类型的对象,相当于下文optLift函数中的那个(a:Option[A])
def map[B](f: A => B):Option[B] = this match{
case None => None // 如果对象类型为None,则直接返回None
case Some(a) => Some(f(a)) // 如果对象类型为Some(a)类型,则分三步:1.解析出a;2. 计算f(a);3. 用Some封装f(a)
}
}
// 从0开始,定义空对象None, case object表示静态对象,数量唯一
case object None extends Option[Nothing]
// 从1开始,定义非空类型Some[+A],case class表示静态类,可直接调用
case class Some[+A](get: A) extends Option[A]
b. Option类型的使用
- 对值进行检验后封装,有错误正常执行并返回None结果:将A转换为Option[A],若A求值时报错,则返回None,否则返回Some[A]
// 通过修改Try参数a为a: => A和 a: A两种情形,使用Try(1 / 0)来验证catch部分是否生效
// 这里对a惰性求值,按需计算,以便在运行过程中,代码运行至try中时对a进行求值来捕获错误,否则将直接返回Some[Exception]对象,进而绕过catch部分
def Try[A](a: => A):Option[A]={
try{Some(a)}catch{case e: Exception => None}
}
- 对函数进行提升:A => B 转换为 Option[A] => Optioin[B]
def test(a: Int): String = a.toString // 构造提升函数对函数A => B进行提升,返回类型为Option[A] => Option[B],因此等号右侧函数实现为(a: Option[A]) => a.map(f): Option[B] def optLift[A, B](f: A => B): Option[A] => Option[B] = (a: Option[A]) => a.map(f) // 等价为以下形式,由于返回函数只有一种类型的入参,等号右侧的参数列表可以省略,入参由_代替,返回参数也可以省略 def optLift[A, B](f: A => B): Option[A] => Option[B] = _.map(f) // 对test函数进行提升 val testOpt = optLift(test)3. Either类型 a. 定义Either类型
定义树状类型的基本过程:
- 定义基本类型;
- 定义用于表示左子树的类型,左子树为错误信息;
- 定义用于表示右子树的类型,右子树为正常值;
// 从trait开始,定义原始类型Either,此例特殊之处在于左右子树互斥
sealed trait Either[+E, +A]{
// 为演示函数提升,需要有map函数,this代表了任意一个继承了Either的类型的对象,相当于下文eitLift函数中的那个(a: Either[E,A])
def map[B](f: A => B):Either[E, B] = this match{
case Left(e) => Left(e) // 当对象类型为Left时,保持不变
case Right(a) => Right(f(a)) // 当对象类型为Right时,则分三步:1.解析出a;2.计算f(a);3. 用Right封装f(a)
}
}
// 定义左子树,只存在左叶子结点,右叶子结点为空
case class Left[+E](value: E) extends Either[E, Nothing]
// 定义右子树,只存在右叶子结点,左叶子结点为空
case class Right[+A](value: A) extends Either[Nothing, A]
b. Either类型的使用
- 对值进行检验后封装,报错时返回错误信息:将A封装为Either[E, A],A不能通过校验时显示报错信息,而不是None
sealed class Name(val value: String)
case class Person(name :Name)
def checkName(name:String):Either[String, Name] = {
if(name == "" || name == null) Left("Name is empty.")
else Right(new Name(name))
}
- 对函数进行提升,报错时返回错误信息:A => B 转换为 Either[E, A] => Either[E, B]
def test(name: Name):Person= Person(name) // 构造提升函数对函数A => B进行提升,返回类型为Either[E, A] => Either[E, B],因此等号右侧函数实现为(a: Either[E, A]) => a.map(f): Either[E, B] def eitLift[E,A,B](f: A => B): Either[E, A] => Either[E, B] = (a: Either[E,A]) => a.map(f) // 等价为以下形式,由于返回函数只有一种类型的入参,等号右侧的参数列表可以省略,入参由_代替,返回参数可以省略 def eitLift[E,A,B](f: A => B): Either[E,A] => Either[E, B] = _.map(f) // 对test函数进行提升 val testEit = eitLift(test)



