本章主要介绍Scala中的模式匹配功能。Scala中的模式匹配很有特色,语法层面上类似JAVA中的分支结构,但功能上要强得多。JAVA分支结构适用于对值作匹配,但Scala中的模式匹配可以对值、类型、集合中的元素等进行匹配,应用的场景很多。模式匹配match case的语法为:
变量v match { case 值 => 代码 }
如果变量v为下划线,则表示不满足所有情况下的默认处理方式,类似JAVA分支中的default语句。其次match-case模式匹配时,只要任一个case分支满足条件,则不会继续判断下一个分支。而在JAVA中,switch-case分支会顺序执行,除非用break关键字阻断。
变量值的模式匹配示例:
def switchProtocol(code: Int) {
code match {
case 1 => println("HTTP")
case 2 => println("HTTPS")
case 3 => println("TCP")
case _ if code > 3 => println("UDP")
case _ => println("SMTP")
}
}
switchProtocol(1)
模式匹配与变量赋值
Scala的模式匹配还支持将未匹配到的默认情况,即下划线,赋值到一个变量中,在具体处理逻辑中可以引用该变量并根据需要进行操作。对上面的例子做些改动:
def switchProtocol(code: Int) {
code match {
case 1 => println("HTTP")
case 2 => println("HTTPS")
case 3 => println("TCP")
case _ if code > 3 => println("UDP")
case _input => println("Not Support Code:" + _input)
}
}
switchProtocol(-1) // 返回Not Support Code:-1
类型的模式匹配
如上述Scala的模式匹配除了支持值匹配之外,还能支持类型匹配。匹配类型的语法形式为:
类型匹配: case 变量:类型 => 代码
读者可以与值匹配的语法形式比较一下,仔细看分析下差异:
值匹配: case 值 => 代码
下面来看一个错误处理的示例:
def onError(e: Exception) {
ematch {
case e1: ArrayIndexOutOfBoundsException
=>printf("ArrayIndexOutOfBoundsException: %s", e1.getMessage)
case e2: ClassNotFoundException
=>printf("ClassNotFoundException: %s", e2.getMessage)
case e3: IllegalArgumentException
=>printf("IllegalArgumentException: %s",e3.getMessage)
case _defult: Exception
=> printf("Exception: %s", _defult)
}
}
onError(newArrayIndexOutOfBoundsException("Index 5 of List@1ac40 is out ofbounds."))
// 返回ArrayIndexOutOfBoundsException: Index 5 of List@1ac40 is out ofbounds.
onError(new ArithmeticException("55/0is not support."))
// 返回Exception: java.lang.ArithmeticException: 55/0 is not support.
关于集合的模式匹配
Scala中还能对集合执行模式匹配,可以对包含特定元素的集合、包含特定元素数量的结合以及对以某些某元素开头的集合进行匹配。下面来看几个例子:
// 对Array集合中的各种模式进行匹配
def contain(array: Array[Int]) {
array match {
// 匹配特定元素
case Array(13) => printf("Contain element.")
// 匹配特定数量
case Array(e1, e2, e3) => printf("Contain 3 elements %s, %s,%s.", e1, e2, e3)
// 匹配特定顺序
case Array(17, _*) => printf("First with element.")
case _ => println("Not Matched.")
}
}
contain(Array(13)) // 返回Contain element.
contain(Array(11)) // 返回First with element.
contain(Array(11, 13, 17)) // 返回Contain 3 elements 11, 13, 17.
contain(Array(11, 13, 17, 19)) // 返回Not Matched.
// 对List集合中的各种模式进行匹配
def validate(list: List[Int]) {
list match { // 通过::符号定义模式
// 匹配特定元素
case 13::Nil => printf("Contain element.")
// 匹配特定数量
case e1::e2::e3::Nil => printf("Contain 3 elements %s, %s,%s.", e1, e2, e3)
// 匹配特定顺序
case 17::tail => printf("First with element.")
case _ => println("Not Matched.")
}
}
validate(List(13)) // 返回Contain element.
validate(List(17)) // 返回First with element.
validate(List(11, 13, 17)) // 返回Contain 3 elements 11, 13, 17.
validate(List(11, 13, 17, 19)) // 返回Not Matched.
Scala中还有一种样例类的概念,有点类似于JAVA中的JavaBean的概念。在样例类中一般只定义属性,并由Scala编译时自动生成getter和setter方法,但是不包含任何方法。样例类的主构造器接收的入参,一般来说不需要使用var或val修饰,Scala自动使用val修饰。此外,Scala会为样例类定义object伴生对象及apply(),该方法接收主构造器中相同入参,并返回样例类的实例。
class Command
case class RpcCommand(serviceId: String,args: String) extends Command
case class LocalCommand(serviceId: String,args: String) extends Command
// 方法中通过样例类型进行匹配
def execute(cmd: Command) {
cmd match {
case RpcCommand(serviceId, args)
=> printf("RPC ServiceId: %s,args: %s", serviceId, args)
caseLocalCommand(serviceId, args)
=> printf("Local ServiceId: %s, args:%s", serviceId, args)
case _ => println("Illegal Command.")
}
}
execute(newRpcCommand("registService", "nginx"))
// 返回RPC ServiceId: registService, args: nginx
execute(new LocalCommand("healthCheck","pod"))
// 返回Local ServiceId: healthCheck, args: pod
最后来分析一下Scala中的特殊类型——Option。Option通常用来校验变量中的值是否为空。Some表示有值,None则表示值为空。示例如下:
// 定义服务注册集合
val registedSvc =Map("Authentication" -> "auth.online.com/sign={1}",
"uploadLog" ->"log.online.com/log={1}",
"healthCheck"-> "hc.online.com/node={1}")
// 根据服务名称调用指定服务
def executeSvc(svcName : String): Unit = {
val svcAddr = registedSvc.get(svcName)
svcAddr match {
case Some(svcAddr) => printf("Service: %s, url: %s",svcName, svcAddr)
case None => printf("Service %s not registed.", svcName)
}
}
executeSvc("Authentication")
// Service: Authentication, url:auth.online.com/sign={1}
executeSvc("mail")
// Service mail not registed.
原文作者:江玮
版权声明:本文版权归作者(译者)及公众号所有,欢迎转载,但未经作者(译者)同意必须保留此段声明,且在文章页面明显位置给出,本文链接如有问题,可留言咨询。