11. case classes 以及模式匹配
11.1 case class
a:在class 前面加上case ,该class 就成为了case class
b:scala 编译器 首先为 这个类添加了一个工厂方法 用来 构造对象 ,
这样允许 用户 不用使用new 就能构造对象
例如:
c:在参数列表中的所有参数都隐含为val,因此 这些参数可以作为 字段加以维护
d:编译器为默认该类添加toString,hashcode equals 方法
e: 编译器为 该类 添加一个copy 方法,返回一个可以修改的copy 对象
11.2 pattern matching 模式匹配
a:定义模式匹配函数
selector match { alternatives }
每个alternatives 都是以case 开始
每个alternatives 都包含 模式 以及表达式,,其中=> 将表达式和模式给分离出来
b:例如:
c: 1.在scala 中match 是一个表达式
2.在scala 中匹配一个pattern ,执行相关的expression,
但是不会执行到 下一个case
3.如果不能匹配到任何一个模式,则会抛出 MatchError 异常
4. 因此 需要为case 定义一个默认 default case ,该case 什么也不处理
例如:
11.3 各种模式
a:_ 通配符匹配任何对象
b:constants pattern 常量模式:
使用常量值作为模式串,例如:
c:variable pattern 变量模式
1.变量模式 就像通配符_一样,匹配任何对象
2.和同配符_不一样的是,变量和任何对象绑定在一起 ,你可以使用这些变量就像object 一样
例如:
d:构造对象模式
对象模式支持 多层的对象构造,也就是 deep match,例如:
e:sequence 模式
1.匹配List 或者Array 这样的顺序类型
2.使用相同的case 语法,但是可以指定模式了的元素个数,
例如:
3.使用_* 匹配任何长度的元素 ,例如:
e:Tuple pattern
例如:
f:Typed Pattern
1.方便做类型测试和类型转换
2.Map[_, _] 类型 在运行时,内部的类型会被同一转成 Object , 因此会碰到类型擦除的问题
3.但是Array[String] Array[Int]由于 在运行其使用的的底层机制是 String[] 或者int[] 类型,因此不会出现类型擦除的问题
例如:
f.绑定变量
1. 变量名e+ 符号@+pattern 的形式,
pattern 完成普通的模式匹配,如果匹配成功,则将 被匹配的对象赋值给指定的变量
例如:
11.4 模式中的条件表达式
a: 在模式中 一个变量只允许出现一次
b:可以在模式中添加if 条件表达式 进行判断
例如:
11.5 pattern overlap 模式交叠
a:pattern 是根据他们写的顺序 进行匹配的。例如:
b:如果编译器检查到 之前的模式已经将所有的模式覆盖了,那么在这个模式之后定义的模式会被标注为unreachable code
11.6 sealed classes
a:为了得到编译器的帮助。列出所欲的模式组合,需要将case class 的父类定义为 sealed
b:加了sealed 关键字的class 除了那些在同一个文件中的子类外不允许添加任何子类
c:如果打算写一些用于模式匹配的类,应该考虑用sealed 封装 这些类的父类
例如:
d:使用unchecked annotation 来避免编译器检查各种模式的组合,避免编译器发出这种警告,“ 表达式:@unchecked”例如
11.7 Option 类型
a:scala 为Option value 提供Option 类型,如果真实的值存在 则返回真实的值,否则返回None object
例如:
11.8 pattern every
1. 在变量定义中的模式 ,例如 在一个赋值中生成多个变量
2.在function 中的case squence, 为构造一个函数提供多个入口,见 Function1
例如:
上述定义其实是 生成一个Function1 类
3.对于下面这种额外的情况: 在使用函数之前要先判断 输入的参数是否满足条件,如果满足,则该函数能够返回正确的值,否则则会抛出异常。对于这样的函数 外面可以定义为 :Parial Function
例如:
4.例如:
second 函数对于list 中的元素<2 时,则会抛出异常。为了避免这种情况,可以将second 定义为Parital Function .
那么在使用这个函数前就可以先用second.isDefinedAt 这个方法先判断是否满足条件,如果满足,之后在调用该函数
5. 表达式中的模式
例如 :
将集合内的元素展开,如果符合指定的模式,则输出,否则 不输出
12.Tuple 元组类型的构造和析构
11.1 case class
a:在class 前面加上case ,该class 就成为了case class
b:scala 编译器 首先为 这个类添加了一个工厂方法 用来 构造对象 ,
这样允许 用户 不用使用new 就能构造对象
例如:
case class Var(name: String)
scala> val v = Var("x")
v: Var = Var(x)
c:在参数列表中的所有参数都隐含为val,因此 这些参数可以作为 字段加以维护
d:编译器为默认该类添加toString,hashcode equals 方法
e: 编译器为 该类 添加一个copy 方法,返回一个可以修改的copy 对象
11.2 pattern matching 模式匹配
a:定义模式匹配函数
selector match { alternatives }
每个alternatives 都是以case 开始
每个alternatives 都包含 模式 以及表达式,,其中=> 将表达式和模式给分离出来
b:例如:
def simplifyTop(expr: Expr): Expr = expr match {
case UnOp("-", UnOp("-", e))
=> e
// Double negation
case BinOp("+", e, Number(0)) => e // Adding zero
case BinOp("*", e, Number(1)) => e // Multiplying by one
case _ => expr
}
c: 1.在scala 中match 是一个表达式
2.在scala 中匹配一个pattern ,执行相关的expression,
但是不会执行到 下一个case
3.如果不能匹配到任何一个模式,则会抛出 MatchError 异常
4. 因此 需要为case 定义一个默认 default case ,该case 什么也不处理
例如:
expr match {
case BinOp(op, left, right) =>
println(expr +" is a binary operation")
case _ =>
}11.3 各种模式
a:_ 通配符匹配任何对象
b:constants pattern 常量模式:
使用常量值作为模式串,例如:
def describe(x: Any) = x match {
case 5 => "five"
case true => "truth"
case "hello" => "hi!"
case Nil => "the empty list"
case _ => "something else"
}
c:variable pattern 变量模式
1.变量模式 就像通配符_一样,匹配任何对象
2.和同配符_不一样的是,变量和任何对象绑定在一起 ,你可以使用这些变量就像object 一样
例如:
expr match {
case 0 => "zero"
case somethingElse => "not zero: "+ somethingElse
}
d:构造对象模式
对象模式支持 多层的对象构造,也就是 deep match,例如:
expr match {
case BinOp("+", e, Number(0)) => println("a deep match")
case _ =>
}
e:sequence 模式
1.匹配List 或者Array 这样的顺序类型
2.使用相同的case 语法,但是可以指定模式了的元素个数,
例如:
expr match {
case List(0, _, _) => println("found it")
case _ =>
}
匹配列表中的前三个元素
3.使用_* 匹配任何长度的元素 ,例如:
expr match {
case List(0, _*) => println("found it")
case _ =>
}
与list 中的第0个元素匹配,而不管这个List 有多长
e:Tuple pattern
例如:
def tupleDemo(expr: Any) =
expr match {
case (a, b, c)
=>
println("matched "+ a + b + c)
case _ =>
}
scala> tupleDemo(("a ", 3, "-tuple"))
matched a 3-tuple
f:Typed Pattern
1.方便做类型测试和类型转换
2.Map[_, _] 类型 在运行时,内部的类型会被同一转成 Object , 因此会碰到类型擦除的问题
3.但是Array[String] Array[Int]由于 在运行其使用的的底层机制是 String[] 或者int[] 类型,因此不会出现类型擦除的问题
例如:
def generalSize(x: Any) = x match {
case s: String => s.length
case m: Map[_, _] => m.size
case _ => -1
}
def isIntIntMap(x: Any) = x match {
case m: Map[Int, Int] => true
case _ => false
}
scala> isIntIntMap(Map(1 -> 1))
res19: Boolean = true
scala> isIntIntMap(Map("abc" -> "abc"))
res20: Boolean = true
scala> def isStringArray(x: Any) = x match {
case a: Array[String] => "yes"
case _ => "no"
}
isStringArray: (x: Any)java.lang.String
scala> val as = Array("abc")
as: Array[java.lang.String] = Array(abc)
scala> isStringArray(as)
res21: java.lang.String = yes
scala> val ai = Array(1, 2, 3)
ai: Array[Int] = Array(1, 2, 3)
scala> isStringArray(ai)
res22: java.lang.String = no
f.绑定变量
1. 变量名e+ 符号@+pattern 的形式,
pattern 完成普通的模式匹配,如果匹配成功,则将 被匹配的对象赋值给指定的变量
例如:
expr match {
case UnOp("abs", e @ UnOp("abs", _)) => e
case _ =>
}
11.4 模式中的条件表达式
a: 在模式中 一个变量只允许出现一次
b:可以在模式中添加if 条件表达式 进行判断
例如:
def simplifyAdd(e: Expr) = e match {
case BinOp("+", x, y) if x == y =>
BinOp("*", x, Number(2))
case _ => e
}
// match only positive integers
case n: Int if 0 < n => ...
// match only strings starting with the letter ‘a’
case s: String if s(0) == 'a' => .
11.5 pattern overlap 模式交叠
a:pattern 是根据他们写的顺序 进行匹配的。例如:
def simplifyAll(expr: Expr): Expr = expr match {
case UnOp("-", UnOp("-", e)) =>
simplifyAll(e)
// ‘-’ is its own inverse
case BinOp("+", e, Number(0)) =>
simplifyAll(e)
// ‘0’ is a neutral element for ‘+’
case BinOp("*", e, Number(1)) =>
simplifyAll(e)
// ‘1’ is a neutral element for ‘*’
case UnOp(op, e) =>
UnOp(op, simplifyAll(e))
case BinOp(op, l, r) =>
BinOp(op, simplifyAll(l), simplifyAll(r))
case _ => expr
}
b:如果编译器检查到 之前的模式已经将所有的模式覆盖了,那么在这个模式之后定义的模式会被标注为unreachable code
11.6 sealed classes
a:为了得到编译器的帮助。列出所欲的模式组合,需要将case class 的父类定义为 sealed
b:加了sealed 关键字的class 除了那些在同一个文件中的子类外不允许添加任何子类
c:如果打算写一些用于模式匹配的类,应该考虑用sealed 封装 这些类的父类
例如:
sealed abstract class Expr
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String,
left: Expr, right: Expr) extends Expr
d:使用unchecked annotation 来避免编译器检查各种模式的组合,避免编译器发出这种警告,“ 表达式:@unchecked”例如
def describe(e: Expr): String = (e: @unchecked) match {
case Number(_) => "a number"
case Var(_)
=> "a variable"
}
11.7 Option 类型
a:scala 为Option value 提供Option 类型,如果真实的值存在 则返回真实的值,否则返回None object
例如:
cala> val capitals =
Map("France" -> "Paris", "Japan" -> "Tokyo")
capitals: scala.collection.immutable.Map[java.lang.String,
java.lang.String] = Map(France -> Paris, Japan -> Tokyo)
scala> capitals get "France"
res23: Option[java.lang.String] = Some(Paris)
scala> capitals get "North Pole"
res24: Option[java.lang.String] = None
scala> def show(x: Option[String]) = x match {
case Some(s) => s
case None => "?"
}
show: (x: Option[String])String
scala> show(capitals get "Japan")
res25: String = Tokyo
scala> show(capitals get "France")
res26: String = Paris
scala> show(capitals get "North Pole")
res27: String = ?
11.8 pattern every
1. 在变量定义中的模式 ,例如 在一个赋值中生成多个变量
scala> val myTuple = (123, "abc")
myTuple: (Int, java.lang.String) = (123,abc)
scala> val (number, string) = myTuple
number: Int = 123
string: java.lang.String = abc
2.在function 中的case squence, 为构造一个函数提供多个入口,见 Function1
例如:
val withDefault: Option[Int] => Int = {
case Some(x) => x
case None => 0
}
scala> withDefault(Some(10))
res28: Int = 10
scala> withDefault(None)
res29: Int = 0
上述定义其实是 生成一个Function1 类
3.对于下面这种额外的情况: 在使用函数之前要先判断 输入的参数是否满足条件,如果满足,则该函数能够返回正确的值,否则则会抛出异常。对于这样的函数 外面可以定义为 :Parial Function
例如:
new PartialFunction[List[Int], Int] {
def apply(xs: List[Int]) = xs match {
case x :: y :: _ => y
}
def isDefinedAt(xs: List[Int]) = xs match {
case x :: y :: _ => true
case _ => false
}
4.例如:
val second: List[Int] => Int = {
case x :: y :: _ => y
}
second 函数对于list 中的元素<2 时,则会抛出异常。为了避免这种情况,可以将second 定义为Parital Function .
val second: PartialFunction[List[Int],Int] = {
case x :: y :: _ => y
}
那么在使用这个函数前就可以先用second.isDefinedAt 这个方法先判断是否满足条件,如果满足,之后在调用该函数
5. 表达式中的模式
例如 :
scala> for ((country, city) <- capitals)
println("The capital of "+ country +" is "+ city)
The capital of France is Paris
The capital of Japan is Tokyo
scala> val results = List(Some("apple"), None,
Some("orange"))
results: List[Option[java.lang.String]] = List(Some(apple),
None, Some(orange))
scala> for (Some(fruit) <- results) println(fruit)
apple
orang
将集合内的元素展开,如果符合指定的模式,则输出,否则 不输出
12.Tuple 元组类型的构造和析构