博客
关于我
Scala模式匹配(match case)
阅读量:128 次
发布时间:2019-02-27

本文共 5886 字,大约阅读时间需要 19 分钟。

Scala的match表达式类似于其他语言中的switch语句,它可以提供给你在多个备选项中做选择。基本上match表达式可以让你使用任意的模式(pattern)做选择。

1. 按值匹配

def valueMatch(fruit: String) {    fruit match {      case "apple" => print("apple")      case "banana" => print("banana")      case "orange" => print("orange")    }}

match表达式检测参数fruit,如果是字符串"apple"就打印"apple",如果是"banana",就打印"banana",如此类推。

2. 按对象类型匹配

def classMatch(obj: Any): Unit = {    obj match {      case x: Int => print(x + " is int")      case x: String => print(x + " is string")      case x: List[Int] => print(x + " is list")    }}

按类型匹配时,case语法为:case 自定义变量名: 要匹配的类类型 => 执行语句。如果不需要在执行语句中使用这个变量,可以把自定义变量名使用下划线(_)代替。需要注意的时当期望匹配目标类型时List, Tuple等含有泛型参数的高阶类型时,由于泛型擦除机制的缘故,无法正确识别参数类型T:

classMatch(List("hello", "ok"))运行结果:List(hello, ok) is list

3. 通配模式

下划线(_)可以用来表示匹配任意的对象。在上面的按值匹配的例子中,如果传入的参数是 "hello",程序会报匹配异常错误,正确的做法是加入下划线(_)匹配,从而忽略掉程序中你不关心的部分:

def valueMatch(fruit: String) {    fruit match {      case "apple" => print("apple")      case "banana" => print("banana")      case "orange" => print("orange")      case _ => print("unknown")     } }

4. 构造器模式

 

与Java的Switch语句比,匹配表达式还有一些重要的差别。其中之一是任意类型的常量,或其他什么东西,都能当成Scala里比较用的样本(Case),而不只是Java的case语句里面的整数类型和枚举常量。另一个区别是在每个备选项的最后并没有break。取而代之的是,break是隐含的,也就是说,不允许从上一个备选项落入到下一个里面去的情况发生。然而,与Java的switch相比,最显著的差别或许是match表达式能产生值。在上面的例子里,match表达式的每个备选项不但可以通过打印输出值,还可以只生成返回值而不打印:

def simpleMatch(fruit: String) {    val name = fruit match {      case "apple" => "apple"      case "banana" => "banana"      case "orange" => "orange"      case _ => "unknown"    }    name }

2. 样本类

带有case修饰符的类被称为样本类(case class),样本类例子如下:

abstract class Animal                                     case class Cat(name: String, kind: String) extends Animal case class Dog(name: String, kind: String) extends Animal

上面的类都没有类结构体,Scala可以去掉围绕空结构体的花括号,因此class c与class c {} 相同。case修饰符可以让scala编译器自动为你的类添加一些句法上的便捷设定。

首先,它会添加与类名一致的工厂方法。构造对象时不再需使用new关键字:

val cat = Cat("tom", "Persian")

第二个便捷设定是样本类参数列表中的所有参数隐式获得了val前缀,因此它被当作字段维护:

val cat = Cat("tom", "Persian")             print(cat.name)

第三,是编译器为你的类添加了方法toString、hashCode 和 equals的自然实现,它们能够打印,哈希和比较由类及(递归地得到)器所有参数组成的整棵树。因为Scala里的==始终直接转到equals,这也就意味着样本类的元素一直是在做结构化的比较。

3. 通配模式

通配模式( _ )匹配任意对象:

val cat = Cat("tom", "Persian")                   cat match {                                         case Cat("tom", "Persian") => print("matched!")   case _ => print("not matched!")                 }matched!val cat = Cat("tom", "Persian")                       cat match {                                             case Cat("jetty", "Persian") => print("matched!")     case _ => print("not matched!")                     }not matched!

通配模式还可以用来忽略对象中你并不关心的部分。比如说,上一个例子实际上并不关心猫的名字和类别,只是检查是否是猫:

val cat = Cat("tom", "Persian")       cat match {                             case Cat(_, _) => print("matched!")   case _ => print("not matched!")     } matched!

match语句中的case 类型一定要是被比较对象的同类型或者子类型,例如下面的语句无法通过编译:

val animal = Dog("erha", "Husky")                           animal match {                                                case Cat(_, _) => print("the animal is a cat!")             case _ => print("the animal is unknown ")                 } Error:(57, 12) constructor cannot be instantiated to expected type; found   : Cat required: Dog      case Cat(_, _) => print("the animal is a cat!")

这是因为变量animal已由Scala的自动类型推导确定为Dog类型,无法实例为Cat类型,需要手动指定变量animal为Animal类型:

val animal: Animal = Dog("erha", "Husky")          animal match {                                       case Cat(_, _) => print("the animal is a cat!")    case _ => print("the animal is unknown ")        }                                                  the animal is unknown

4. 常量模式

常量模式仅匹配自身。任何字面量都可以用作常量,任何的val或单例对象也可以用作常量。例如,单例对象Nil只匹配空列表模式。

scala>   def describe(x: Any) = x match {           case 5 => "five"           case true => "truth"           case "hello" => "hi!"           case Nil => "the empty list"           case _ => "something else"         }

5. 变量模式

变量模式类似于通配符,可以匹配任意对象。不过与通配符不同的地方在于,Scala把变量绑定在匹配的对象上。因此之后你可以使用这个变量操作对象。

val animal: Animal = Dog("erha", "Husky")            animal match {                                         case Cat(_, _) => print("the animal is a cat!")      case other => print("the animal is: " + other)     }    the animal is: Dog(erha,Husky)

6. 序列模式

你也可以像匹配样本类那样匹配如List或Array这样的序列类型。下面的例子展示了检查开始于零的三元素列表的模式:

expr match {                                   case List(0, _, _) => print("found it!")     case _ =>                                  }

如果你想匹配一个不指定长度的序列,可以使用_*作为最后的元素。这种模式能匹配序列中零到任意数量的元素:

expr match {                                case List(0, _*) => print("found it!")    case _ =>                               }

7. 模式守卫

模式守卫接在模式之后,开始于if,后接Boolean表达式:

val animal: Animal = Dog("erha", "Husky")         animal match {                                      case Dog(name, kind) if kind.equals("Husky") =>   case other => print("the animal is: " + other)  }

8. 封闭类

一旦你写好了模式匹配,你就需要确认已经考虑到了所有的情况。例如,定义了一个抽象类和n个子样本类,你想要在模式匹配语句中考虑所有子类型组合。通常,这在Scala是不可能的,因为新的样本子类可以在任意新的文件内被定义。可选方案就是让样本类的超类被封闭(sealed)。封闭类除了类定义所在文件之外不能再添加任何子类

sealed abstract class Animalcase class Cat(name: String, kind: String) extends Animal case class Dog(name: String, kind: String) extends Animal

9. Option类型

Scala为可选值定义了一个名为Option的标准类型。这种值可以有两种形式。可以是Some(x)的形式,其中x是实际值,或者可以是None对象,代表缺失的值。

def show(x: Option[String]) = x match {    case Some(x) => x    case None => "?"}

上面代码背后的原理还是Scala的类型匹配,因为Some类和None类都是Option的子类,Scala源码中定义如下:

final case class Some[+A](x: A) extends Option[A] {  def isEmpty = false  def get = x}case object None extends Option[Nothing] {  def isEmpty = true  def get = throw new NoSuchElementException("None.get")}

10. 模式在变量定义中

在定义val或var的任何时候,都可以使用模式替代简单的标识符。例如,你可以使用模式拆分元组并把其中的每个值分配给变量:

val myTuple = ("abc", 123)val (string, number) = myTupleval dog = Dog("erha", "Husky")val Dog(name, kind) = dog

11. for表达式里的模式

for((country, city) <- capitals) {      println("the capital of " + country + " is " + city) }

 

转载地址:http://btub.baihongyu.com/

你可能感兴趣的文章
mysql deadlock found when trying to get lock暴力解决
查看>>
MuseTalk如何生成高质量视频(使用技巧)
查看>>
mutiplemap 总结
查看>>
MySQL DELETE 表别名问题
查看>>
MySQL Error Handling in Stored Procedures---转载
查看>>
MVC 区域功能
查看>>
MySQL FEDERATED 提示
查看>>
mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
查看>>
Mysql group by
查看>>
MySQL I 有福啦,窗口函数大大提高了取数的效率!
查看>>
mysql id自动增长 初始值 Mysql重置auto_increment初始值
查看>>
MySQL in 太多过慢的 3 种解决方案
查看>>
MySQL InnoDB 三大文件日志,看完秒懂
查看>>
Mysql InnoDB 数据更新导致锁表
查看>>
Mysql Innodb 锁机制
查看>>
MySQL InnoDB中意向锁的作用及原理探
查看>>
MySQL InnoDB事务隔离级别与锁机制深入解析
查看>>
Mysql InnoDB存储引擎 —— 数据页
查看>>
Mysql InnoDB存储引擎中的checkpoint技术
查看>>
Mysql InnoDB存储引擎中缓冲池Buffer Pool、Redo Log、Bin Log、Undo Log、Channge Buffer
查看>>