Scala编程——第11章:模式匹配和样例类(下)


本节学习样例类的相关知识。有关模式匹配的知识点击阅读: 模式匹配

一、样例类

1.基本介绍

样例类是一种特殊的类,主要用于优化模式匹配。

  1. 样例类仍然是类
  2. 样例类用case关键字进行声明
  3. 样例类是为模式匹配而优化的类
  4. 构造器中的每一个参数都成为val——除非它被显式地声明为var(不建议这样做)。
  5. 在样例类对应的伴生对象中提供apply方法,让你不用new关键字就能构造出相应的对象。
  6. 提供unapply方法让模式匹配可以工作。
  7. 将自动生成toString、equals、hashCode和copy方法(类似模板类,直接给生成,方便使用)。
  8. 除上述外,样例类和其他类完全一样。你可以添加方法和字段,扩展它们。

2.应用案例

背景:编写一个操作算术表达式的类库。为保持简单,我们将注意力集中在由变量、数,以及一元二元操作符组成的算术表达式上。

用Scala的类层次结构表达:如下代码所示:

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 

在这里插入图片描述

①样例类

类层次结构包括一个抽象的基类 Expr 和 四个子类,每一个子类都表示我们要考虑的一种表达式。五个类的定义体都是空的,Scala 允许我们省去空定义体的花括号, class C 和 class C {} 是相同的。

  • case 修饰的类就是样例类(case class),所以上述案例有四个样例类
  • 样例类会添加一个跟类同名的工厂方法:apply(),可以不用new关键字就可以构造新的对象
    在这里插入图片描述
    当你需要嵌套定义时,工厂方法尤为有用。不用new关键字,可以一眼就看明白表达式的结构
    在这里插入图片描述
  • 样例类中参数列表中的每个参数都隐式的获得了一个val前缀,所以可以当做字段处理
    在这里插入图片描述
  • 样例类会自动实现toString、hashCode、equals和copy 方法。(Scala用 == 代替equlas 比较对象相等性)

你只需要多写一个 case 修饰符,就可以获得样例类带来的巨大便利,生成了额外的方法的同时,对于构造方法的每个参数都隐式地添加了字段。 不过,样例类最大的好处是它们支持模式匹配

②模式匹配

假定我们想简话前面展示的算术表达式。可用的简化的规则非常多,下只列举一部分:

UnOp("-", UnOp ("-", e)) => e 	//双重取负
BinOp("+",  e, Number(0)) => e //加0
BinOp("*", e, Number(1))  => e // 乘1

用模式匹配定义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
}

执行结果:
simplifyTop(UnOp (”-”, UnOp (”-”, Var(”x”))))
在这里插入图片描述

3.简单案例

上述编写一个操作算术表达式的类库的案例,对与初学者来说可能存在一定难度,在模式匹配中使用了多种模式,一时难以理解。下面来看一个稍微简单一点的案例

在本例中,我们有两个继承于常规类Amount类的样例类

abstract class Amount
case class Dollar(vaule: Double) extends Amount //美元类
case class Currency(vaule: Double, unit: String) extends Amount //货币类

我们也可以有针对单例的样例对象:

case object Nothing extends Amount

在这里插入图片描述

当我们有一个类型为Amount的对象时,我们可以使用模式匹配来匹配到它的类,并将属性值绑定到变量:

for(amt <- Array(Dollar(10000.0), Currency(10000.0, "RMB"),Nothing)){
	val res = amt match{
		case Dollar(v) => "美元:$"+v
		case Currency(v,u) => "人民币:"+v+" "+u
		case _ => "nothing"
	}
	println(amt +":"+res)
}

执行结果:
在这里插入图片描述

三、匹配嵌套结构

样例类经常被用于嵌套结构。例如:某个商品售卖的物品。有时会将物品捆绑在一起打折出售。

abstract class Item
case class Article(description: String, price: Double) extends Item
case class Bundle(description: String, discount: Double, items: Item*) extends Item

因为不用使用new,所以我们可以很容易的给出嵌套对象的定义:

Bundle("Father's day special",20.0,
		Article("Scala for the Impatient",39.9),
		Bundle("Anchor Distillery Sampler", 11.1,
			Article("Old Potrero Straight", 79.8),
			Article("Junipero Gin",32.95)
	)
)

模式匹配可以匹配到特定的嵌套。 比如:

case Bundle(_, _, Article(dsec,_), _*) => ....

上述代码将desc绑定到Bundle的一个Article的描述。

在这里插入图片描述

四、密封类

当你使用样例类来做模式匹配时,你可以想让编译器确保你已经列出了所有可能的选择。你需要将样例类的通用超类声明为sealed

sealed abstract class Amount
case class Article(description: String, price: Double) extends Item
case class Bundle(description: String, discount: Double, items: Item*) extends Item

密封类的所有子类都必须在与改密封类相同的文件中定义。例如:假设想要添加一个新的美食书类作为另一个样例类:

case class food(description: String, price: Double) extends Item

这个样例类必须在Item所在的文件中定义。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页