一、介绍
内容
Java 语言中,在运行时将特定的功能绑定在对象上,是修饰模式的核心。而在 Scala 中,又如何进行模式的限定修饰呢?本节我们将着重介绍如何进行模式限定修饰和重叠模式的定义。
知识点
- 模式限定修饰
- 重叠模式定义
环境
- Scala 2.11.8
- Xfce 终端
适合人群
本课程难度为一般,属于初级级别课程,适合 Scala 编程基础的用户。
二、开发准备
为了使用交互式 Scala 解释器,你可以在打开的终端中输入命令:
su -l hadoop
scala
当出现scala>
开始的命令行提示符时,就说明你已经成功进入解释器了。如下图所示。
本实验的所有命令及语句均可在 Shell 中输入。
三、步骤
3.1 模式限定修饰
有些时候,需要对定义的模式做某些限制,比如你需要完成表达式简化,比如两个相同的参数相加 e+e
,你想把它简化为 e*2
。也就是:
BinOp("+",Var("x"),Var("x"))
转化为:
BinOp("*",Var("x"),Number(2))
你可能试着这么定义规则:
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
def simplifyAdd(e:Expr) =e match{
case BinOp("+",x,x) => BinOp("*",x,Number(2))
case _ =>
}
但是编译器会报错:
<console>:13: error: x is already defined as value x
case BinOp("+",x,x) => BinOp("*",x,Number(2))
编译器会告诉你变量 x
已经定义过了,也是模式中定义的变量名只能定义一次,那么此时就可以借助于限制修饰,我们重新定义如下:
def simplifyAdd(e:Expr) = e match{
case BinOp("+",x,y) if x==y => BinOp("*",x,Number(2))
case _ =>
}
模式的限定修饰为一个 if
语句, if
语句可以使用任意的布尔表达式。通常这个布尔表达式对前面定义的模式变量进行了限制。也就是说,只有在条件满足且满足模式匹配的情况下,才执行 =>
后面的表达式。
尝试在 Scala Shell 中输入如下语句,测试一下:
scala> simplifyAdd(BinOp("+",Var("x"),Var("x")))
res0: Any = BinOp(*,Var(x),Number(2.0))
3.2 重叠模式定义
Scala 在匹配模式时,按照模式定义的顺序依次检查,因此越特定的规则越要先定义,而通用的规则后定义。比如我们修改之前的定义的 simplifyTop
:
def simplifyTop(expr :Expr) :Expr = expr match {
case UnOp("-",UnOp("-",e))=>e
case BinOp("+",e,Number(0))=>e
case BinOp("*",e,Number(1))=>e
case _ => expr
}
要使它可以简化任意层次的表达式,我们需要添加两个通用的规则,定义如下:
def simplifyAll(expr :Expr) :Expr = expr match {
case UnOp("-",UnOp("-",e))=>e
case BinOp("+",e,Number(0))=>e
case BinOp("*",e,Number(1))=>e
case UnOp(op,e) => UnOp(op,simplifyAll(e))
case BinOp(op,l,r)=>BinOp(op,simplifyAll(l),simplifyAll(r))
case _ => expr
}
simplifyAll
规则 1 是规则 4 的特例,而规则 2、3 是规则 5 的特例,因此 1、2、3 需要定义在 4、5 之前,而最后的缺省规则需要放在最后。如果顺序反了,比如把通用的规则放在了特例之前,编译器会给出警告。因为当 Scala 做匹配时,按照规则定义的顺序,首先会匹配通用规则,若规则匹配成功,那么后面的特例就没有机会匹配。比如:
def simplifyBad(expr:Expr):Expr = expr match{
case UnOp(op,e) => UnOp(op,simplifyBad(e))
case UnOp("-",UnOp("-",e))=>e
}
<console>:12: warning: unreachable code
case UnOp("-",UnOp("-",e))=>e
^
simplifyBad: (expr: Expr)Expr
四、总结
就功能而言,相对于生成子类,修饰模式显得更为灵活,于是我们可以给某个对象添加一些功能,而不是为整个类。本节学习的模式限定修饰以及重叠模式定义会经常用到,不妨想想现实生活中有哪些例子可以应用到本节的这两个知识点。
本文由 liyunfei 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 24,2022