1. 模式匹配
1、模式匹配是Scala中非常强大的一种功能。模式匹配,其实类似于Java中的switch case语法,即对一个值进行条件判断,然后针对不同的输入条件,进行结果处理。
2、Scala的模式匹配的功能比Java的switch case语法的功能要强大地多,Java的switch case语法只能对值进行匹配。但是Scala的模式匹配除了可以对值进行匹配之外,还可以对类型进行匹配、对Array和List的元素情况进行匹配、对case class进行匹配、甚至对有值或没值(Option)进行匹配。
模式匹配常见的语法结构如下:
变量 match {
case 可能性1 => 操作1
。。。
case 可能性N => 操作N
case _ => 默认/其它操作
}
1.1. 可以用到Switch语句中
Scala强大的模式匹配机制,可以应用在switch语句、类型检查以及“析构”等场合。
//使用模式匹配完成switch的操作
var sign = 0
val ch = '+'
ch match {
case '-' => sign = -1
case '*' => sign = -2
case '+' => sign = 0
case _ => sign = 1
}
/*
* switch(ch) {
* case '+' :
* sign = 0;
* break;
* case '-' :
* sign = -1;
* break;
* case '*' :
* sign = -2;
* break;
* default:
* sign = 1;
* break;
* }
*/
println("sign=" + sign)
//scala中的每一个表达式都有返回值,默认最后一句话就是返回值
sign = ch match {
case '-' => -1
case '*' => -2
case '+' => 0
case _ => 1
}
println("sign=" + sign)
1.2. 守卫
像for表达式一样,match也提供守卫功能,守卫可以是任何Boolean条件 match 守卫功能
def caseOps2: Unit = {
var sign = 0
val ch = '-'
val ret = ch match {
case '-' => sign = -1
case '*' => sign = -2
case _ if Character.isDigit(ch) => 3
case _ => sign = 1
}
println("ret = " + ret)
}
1.3. 模式中的变量和类型模式
模式匹配中的变量,需要从语法结构说起:
变量 match {
case 可能性1 => 操作1
。。。
case 可能性N => 操作N
case _ => 默认/其它操作
}
启动如果是匹配的类型,可以将可能性x书写为==> 变量:类型,可能性以就成为=>变量1:类型1,这样做的好处是什么呢?就是直接进行类型转换,可以方便操作其特有的api。
如果类型时确定的,可以将:后面的类型省略掉。
-
变量
def caseOps3: Unit = { "Hello world~".foreach(c => println( c match { case ' ' => "space" case ch => "Char: " + ch } )) }
-
类型
val input:Any = StdIn.readLine("请输入内容:") // input.isInstanceOf // input.asInstanceOf input match { case i:Int => println("int i = " + i) case s:String => println("String s = " + s) case ch:Char => println("char ch = " + ch) case _ => println(input) }
1.4. 匹配数组、列表和元组
val array = Array(0, -5)
array match {
//匹配数组有2个元素,分别将两个元素赋值给x和y
case Array(x, y) => println(s"x=$x, y=$y")
//匹配数组以0开头
case Array(0, _*) => println("Array(0, _*)")
//默认的匹配,如果匹配不到,scala.MatchError
case _ => println("default")
}
1.5. 样例类
所谓样例类,就是case class,是scala中一种专门用来携带数据的class,类似于java中的javabean,一般的定义方式需要定义该case class的主构造器,其所有的字段都在主构造器中完成声明,case class自动会提供所谓getter和setter方法。
case class的主构造函数接收的参数通常不需要使用var或val修饰,Scala自动就会使用val修饰(但是如果你自己使用var修饰,那么还是会按照var来)
Scala自动为case class定义了伴生对象,也就是object,并且定义了apply()方法,该方法接收主构造函数中相同的参数,并返回case class对象
def caseOps6: Unit = {
abstract class Expr //抽象类 表达式
case class Var(name:String) extends Expr
case class UnOp(expr:Expr, operator:String) extends Expr
case class Number(num:Double) extends Expr
case class BinOp(left:Expr, operator:String, right:Expr) extends Expr
def test(expr:Expr) = {
expr match {
case Var(name) => println("Var: " + name)
case Number(num) => println("Number: " + num)
case UnOp(Var(name), "+") => println(name + "+")
case BinOp(Number(num1), "+", Number(num2)) => println(num1 + num2)
case BinOp(Number(num1), "-", Number(num2)) => println(num1 - num2)
case BinOp(Number(num1), "*", Number(num2)) => println(num1 * num2)
case _ => println(expr)
}
}
test(BinOp(Number(3.0), "-", Number(5.2)))
}
1.6. 模拟枚举
-
枚举的一般定义方式
object _02EnumrationOps { def main(args: Array[String]): Unit = { def accrossRoad(light: TrafficLight.Value): Unit = { light match { case TrafficLight.GREEN => println("畅行无阻,及时通过") case TrafficLight.YELLOW => println("hurry up") case TrafficLight.RED => println("行车不规范,亲人泪两行") case _ => println("翻车了") } } accrossRoad(TrafficLight.GREEN) } } //普通的枚举的定义 object TrafficLight extends Enumeration { val GREEN, YELLOW, RED = Value }
-
枚举的模式匹配方式
sealed class密封类,一个类的所有的子类型都是已知的,都必须要在定义期间给出 当然一般这个sealed class密封类通常会被声明为抽象,使用子类来完成具体构建 密封类的所有子类都必须在与该密封类相同的文件中定义。 如果某个类是密封的,那么在编译期所有的子类是可知的,因而可以检查模式语句的完整性。 让所有同一组的样例类都扩展某个密封的类或特质是个好的做法。
sealed abstract class TrafficLight(color:String) case class RED(red:String) extends TrafficLight(red) case class GREEN(green:String) extends TrafficLight(green) case class YELLOW(yellow:String) extends TrafficLight(yellow) val light:TrafficLight = RED("酒后来驾车,亲人泪两行") light match { case RED(red) => println(red) case GREEN(green) => println(green) case YELLOW(yellow) => println(yellow) }
1.7. Option
Option是scala中有值(Some)或者没有值(None)的类型,scala也可以对应Option进行模式匹配进行处理。
val map = Map[String, String](
"China" -> "BJ",
"India" -> "XDL",
"Japan" -> "Tokyo"
)
map.get("India") match {
case Some(capital) => println("India's capital is " + capital)
case None => println("所查国家不存在")
}