Scala强大的模式匹配机制,可以应用在switch语句、类型检查以及“析构”等场合。样例类对模式匹配进行了优化。
更好的switch
|
varsign=...
valch:Char=...
chmatch{
case'+'=>sign=1
case'-'=>sign=-1
case_=>sign=0
}
|
上面代码中,case _模式对应于switch语句中的default,能够捕获剩余的情况。如果没有模式能匹配,会抛出MatchError。而且不像常见的switch语句,在一种模式匹配之后,需要使用break来声明分支不会进入下一个分支。
match是表达式,不是语句,所以是有返回值的,故可将代码简化:
|
sign=chmatch{
case'+'=>1
case'-'=>-1
case_=>0
}
|
match表达式中可以使用任何类型。模式总是从上往下进行匹配。
守卫
看代码就好,与if表达式的守卫相同作用:
|
chmatch{
case'+'=>sign=1
case'-'=>sign=-1
case_ifCharacter.isDigit(ch)=>digit=Character.digit(ch,10)
case_=>sign=0
}
|
模式中的变量
如果在case关键字后跟着一个变量名,那么匹配的表达式会被赋值给那个变量。case _是这个特性的一个特殊情况,变量名是_。
|
"Hello, world"foreach{c=>println(
cmatch{
case' '=>"space"
casech=>"Char: "+ch
}
)}
|
经过我的尝试,在如果变量名是_,那么在=>后使用_是不行的。
在模式中使用变量可能会与常量冲突。
|
importscala.math._
xmatch{
casePi=>...
...
}
|
在上面的代码中,要如何判断Pi这个标志符是一个用来匹配的常量还是模式中的变量?规则是:变量比需要以小写字母开始。如果有常量是小写字母开头的,那么需要用反引号将常量名包起来:
|
importjava.io.File._
strmatch{
case`pathSeparator`=>...
...
}
|
类型模式
相比使用isInstanceOf来判断类型,使用模式匹配更好。
|
objmatch{
casex:Int=>x
cases:String=>Integer.parseInt(s)
case_:BigInt=>Int.MaxValue
case_=>0
}
|
在匹配类型时,需要使用一个变量名,否则就是使用对象本身来进行匹配了。
|
objmatch{
case_:BigInt=>Int.MaxValue // 匹配任何类型为BigInt的对象
caseBigInt=>-1 // 匹配类型为Class的BigInt对象
}
|
因为匹配是发生在运行期的,而且JVM中泛型的类型信息会被擦掉,因此不能使用类型来匹配特定的Map类型(大部分集合类型也都不可以吧):
|
casem:Map[String,Int]=>... // 不行
casem:Map[_,_]=>... // 匹配通用的Map,OK
|
但对于数组来说,类型信息是完好的,所以可以在Array上匹配。
匹配数组、列表和元组
|
arrmatch{
caseArray(0)=>"0" // 匹配包含0的数组
caseArray(x,y)=>x+" " +y // 匹配任何带有两个元素的数组,并将元素绑定到x和y
caseArray(0,_*)=>"0 ..." // 匹配任何以0开始的数组
case_=>"something else"
}
|
下面的模式匹配,功能与上面的代码是一样的,不过将数组换成了列表。
|
lstmatch{
case0::Nil=>"0"
casex::y::Nil=>x+" "+y
case0::tail=>"0 ..."
case_=>"something else"
}
|
与上面两个例子差不多,模式匹配也可以使用在元组上。
注意到变量将会被绑定到这三种数据结构的不同部分上,这种操作被称为“析构”。
提取器
在上一节中,使用模式匹配来对数组、列表和元组进行了匹配,在这个过程的背后的是提取器(extractor)机制。使用unapply来提取固定数量的对象,使用unapplySeq来提取一个序列。
在前面的代码 case Array(0, x) => ...中, Array(0, x)部分实际上是使用了伴生对象中的提取器,实际调用形式是: Array.unapplySeq(arr)。根据Doc,提取器方法接受一个Array参数,返回一个Option。
正则表达式是另一个适用提取器的场景。正则有分组时,可以用提取器来匹配分组:
|
valpattern="([0-9]+) ([a-z]+)".r
"99 bottles"match{
casepattern(num,item)=>...
}
|
变量声明中的模式
在变量声明中的模式对于返回对偶(更广一点也可以用在元组上吧?)的函数来说很有用。
|
val(x,y)=(1,2)
val(q,r)=BigInt(10)/%3 // 返回商和余数的对偶
valArray(first,second,_*)=arr // 将第一和第二个分别给first和second
|
for表达式中的模式
这一部分的内容多在介绍for表达式时提过了,不过当时并没有意识到使用的是模式。
|
importscala.collection.JavaConversions.propertiesAsScalaMap
for((k,v)<-System.getProperties()) // 这里使用了模式
println(k+" -> "+v)
for((k,"")<-System.getProperties()) // 失败的匹配会被忽略,所以只打印出值为空的键
println(k)
|
样例类
样例类是种特殊的类,经过优化以用于模式匹配。
|
abstractclassAmount
// 继承了普通类的两个样例类
caseclassDollar(value:Double)extendsAmount
caseclassCurrency(value:Double,unit:String)extendsAmount
// 样例对象
caseobjectNothing extendsAmount
|
使用:
|
amtmatch{
caseDollar(v)=>"$"+v
caseCurrency(_,u)=>"Oh noes, I got "+u
caseNothing=>"" // 样例对象没有()
}
|
在声明样例类时,下面的过程自动发生了:
- 构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;
- 在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;
- 提供unapply方法使模式匹配可以工作;
- 生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。
除了上述之外,样例类和其他类型完全一样,方法字段等。
copy方法和带名参数
样例类的copy方法创建一个与现有对象相同的新对象。可以使用带名参数来修改某些属性:
|
valamt=Currency(29.95,"EUR")
valprice=amt.copy(values=19.95)
valprice=amt.copy(unit="CHF")
|
case语句中的中置表示法
如果unapply方法产出一个对偶,则可以在case语句中使用中置表示法。对于有两个参数的样例类,可以使用中置表示法。
|
amtmatch{caseaCurrencyu=>...} // 等于case Currency(a, u)
|
这个特性的本意是要匹配序列。举例,List对象要么是Nil,要么是样例类::。所以可以:
|
lstmatch{caseh::t=>...} // 等同于case ::(h, t),调用::.unapply(lst)
|
多个中置表达式放在一起时会比普通的形式更加易读。
匹配嵌套结构
这个解释起来有点绕。
|
abstarct classItem
caseclassArticle(description:String,price:Double)extendsItem
caseclassBundle(description:String,price:Double,items:Item*)extendsItem
Bundle("Father's day special",20.0,
Article("Scala for the Impatient",39.95),
Bundle("Anchor Distillery Sampler",10.0,
Article("Old Potrero Straight Rye Whisky",79.95),
Article("Junipero Gin",32.95)
)
)
|
模式可以匹配到特定的嵌套:
|
caseBundle(_,_,Article(descr,_),_*)=>...
|
上面的代码中descr这个变量被绑定到第一个Article的description。另外还可以使用@来将值绑定到变量:
|
// art被绑定为第一个Article,rest是剩余的Item序列
caseBundle(_,_,art@Article(_,_),rest@_*)=>...
|
下面是个使用了模式匹配来递归计算Item价格的函数。
|
defprice(it:Item):Double=itmatch{
caseArticle(_,p)=>p
caseBundle(_,disc,its@_*)=>its.map(price_).sum-disc
}
|
密封类
当使用样例类来做模式匹配时,如果要让编译器确保已经列出所有可能的选择,可以将样例类的通用超类声明为sealed。
密封类的所有子类都必须在与该密封类相同的文件中定义。
如果某个类是密封的,那么在编译期所有的子类是可知的,因而可以检查模式语句的完整性。
让所有同一组的样例类都扩展某个密封的类或特质是个好的做法。
模拟枚举
可以使用样例类来模拟枚举类型:
|
sealedabstractclassTrafficLightColor
caseobjectRedextendsTrafficLightColor
caseobjectYellowextendsTrafficLightColor
caseobjectGreenextendsTrafficLightColor
colormatch{
caseRed=>"stop"
caseYellow=>"hurry up"
caseGreen=>"go"
}
|
Option类型
Option类型用来表示可能存在也可能不存在的值。样例子类Some包装了某个值,而样例对象None表示没有值。Option支持泛型。
|
scores.get("Alice")match{
caseSome(score)=>println(score)
caseNome=>println("No score")
}
|
偏函数(L2)
被包在花括号内的一组case语句是一个偏函数。
偏函数是一个并非对所有输入值都有定义的函数,是PartialFunction[A, B]类的一个实例,其中A是参数类型,B是返回类型。该类有两个方法:apply方法从匹配的模式计算函数值;isDefinedAt方法在输入至少匹配其中一个模式时返回true。
|
valf:PartialFunction[Char,Int]={case'+'=>1;case'-'=>-1}
f('-') // 返回-1
f.isDefinedAt('0') // false
f('0') //抛出MatchError
|
相关推荐
scala可以使用模式匹配来匹配样例类,从而可以快速获取样例类中的成员数据。后续,我们在开发Akka案例时,还会用到。 示例 需求说明 创建两个样例类Customer、Order Customer包含姓名、年龄字段 Order包含id字段 ...
#### 七、样例类与特质的结合 ```scala trait Sex case object Male extends Sex case object Female extends Sex case class Student7(name: String, sex: Sex) object Demo7 { def main(args: Array[String]): ...
2. **构造函数模式**:可以匹配样例类实例,如 `case C(a, b)`。 3. **提取器模式**:使用 `unapply` 方法定义的自定义模式,可以解析复杂的对象结构。 4. **变量模式**:直接使用变量名作为模式,匹配成功时将值...
最邻近匹配(Nearest Neighbor Matching,NNM)是一种在机器学习、图像处理和模式识别领域广泛应用的技术。在MATLAB环境中,NNM通常用于寻找数据集中与特定查询点最相似的点,以此来进行分类或回归任务。在这个上下...
本课程内容涵盖多个关键概念,如模式匹配、样例类、隐式函数和异常处理及泛型,这些都是Scala语言强大特性的体现。 首先,Scala的模式匹配是一种强大的控制流构造,类似于Java中的switch语句,但更为灵活。它允许...
此文档是scala的语法大全,一共分为22章,控制结构,特质,高阶函数,集合,模式匹配,样例类,解析,actor等都包括在内。
12. **模式匹配和样例类**:模式匹配用于解构复杂数据结构,如匹配枚举值、拆解元组等。样例类(Case Class)是Scala中用于简化模式匹配的特殊类,具有默认的构造函数、equals、hashCode和toString方法。 通过学习...
模板匹配是一种图像处理技术,用于在大图中寻找与模板图像相似的小区域。在C#中,通过Emgu.CV库可以很容易地实现这一功能。首先,我们需要加载大图和模板图像,然后调用`MatchTemplate`方法进行匹配,最后通过`...
接着初始化cURL资源,设置URL及相关选项:不返回头部信息、开启二进制传输模式、自动引用和跟随重定向。这些设置确保能完整下载任何类型文件。最后,执行cURL请求并将文件保存到本地。 4. **Alexa/Google Page Rank...
在处理文本数据和模式匹配时,正则表达式(Regular Expressions)是不可或缺的工具。正则表达式允许程序员通过简洁的语法来匹配、查找、替换和分析字符串中的模式。在Delphi中,我们可以使用TRegEx类来实现正则...
Scala编程语言由著名计算机科学家马丁·奥德斯...随着深入学习,你将探索控制结构、数组、元组、类与对象、继承、特质、模式匹配、样例类、函数及抽象化、集合以及隐式转换等高级概念,为Spark开发和阅读源码做好准备。
提交表单时,服务器会检查用户输入的验证码是否与会话中存储的验证码匹配。如果匹配,登录过程将继续;如果不匹配,用户将收到错误消息并被要求重新输入。 在这个压缩包中,"testRondom"很可能是一个Servlet类的...
- **样例类**:样例类是一种特殊的类,主要用于模式匹配。当定义为样例类时,Scala会自动生成一系列有用的方法,如`equals`、`hashCode`等。 - **Option类型**:用于表示可能为空的值,是Scala处理空值的一种方式。 ...
3. **面向对象编程**:介绍类的定义、对象的创建与销毁,封装、继承、多态等面向对象的基本概念,以及类的方法(包括构造函数`__init__`、析构函数`__del__`、属性访问器`__getattribute__`等特殊方法)。...
在计算机视觉领域,图片识别通常涉及机器学习和深度学习技术,如特征提取、模式匹配或神经网络模型。 描述中提到是“java程序编写的图片识别样例程序,附简单demo仅供参考”,这意味着该程序不仅包含实际的代码实现...
4. **Scala编程基础**:复习Scala的变量、函数、类、对象、模式匹配等基础语法,这对于编写Spark应用是必要的。 5. **Spark SQL**:学习如何创建DataFrame,执行SQL查询,以及数据转换操作。这在数据分析和ETL...
第14章 模式匹配和样例类 A2 221 14.1 更好的switch 222 14.2 守卫 223 14.3 模式中的变量 223 14.4 类型模式 224 14.5 匹配数组、列表和元组 225 14.6 提取器 227 14.7 变量声明中的模式 227 14.8 for...
- **样例类**:样例类用于伴生对象和模式匹配,可以方便地创建类的实例。 **4. Scala在大数据中的角色** 随着大数据处理的需求增加,Scala在Apache Spark中的核心地位使其变得尤为重要。Spark使用Scala编写,提供...
在这个“待审核的广告营销文本样例”压缩包中,提供了大量可能用于训练模型的数据。 首先,我们要对这些文本进行预处理。预处理是机器学习中的关键步骤,它包括去除无关字符(如标点符号、数字)、词干提取、词形...
- **样例类**:样例类是Scala中一种特殊的类,主要用于模式匹配。它们自动实现了许多有用的特性,如`equals`、`hashCode`和`toString`等方法。 #### 总结 Scala作为一种强大的编程语言,以其优雅的语法、丰富的...