快学Scala笔记(五)
来源:互联网 发布:上海大学图书馆数据库 编辑:程序博客网 时间:2024/06/06 02:39
十四、模式匹配和样例类
var sign = ...var ch: Char = ...ch match { case '+' => sign = 1 case '-' => sign = -1 case _ => sign = 0 // 否则代码会抛出MatchError异常}
守卫
ch match { case '+' => sign = 1 case '-' => sign = -1 case _ if Charactor.isDigit(cn) => digit = Charactor.digit(ch, 10) case _ => sign = 0}
守卫可以是任何Boolean条件
模式中的变量
case 关键字后接一个变量,那么匹配的表达式会赋值给这个变量
str(i) match { case '+' => sign = 1 case '-' => sign = 01 case ch => digit = Character.digit( ch, 10 )}
case ch if Character.isDigit(ch) => digit = Character.digit( ch, 10 )
变量模式可能会与常量表达式发生冲突
import scala.math._x match { case Pi => ... // 变量必须以小写字母开头 case `pathSeperator` => ... // 小写字母开头的常量}
类型模式
可以匹配表达式的类型
obj match { case x: Int => x case s: String => Integer.parseInt(s) case _: BigInt => Int.MaxValue case _ => 0}
在类型匹配的时候必须给一个变量名,否则会拿对象本身来匹配
匹配发生在运行期,Java虚拟机中泛型的类型信息是被擦掉的,因此不能用类型来匹配特定的Map类型
case m : Map[String, Int] => ... // 错误!case m : Map[_, _] => ... // OK
匹配数组、列表和元组
attr match { case Array(0) => "0" // 匹配包含0的数组 case Array(x, y) => x + " " + y // 匹配任何带有两个元素的数组 case Array(0, _*) => "0 ..." // 匹配任何以0开始的数组 caes _ => "somthing else"}
匹配List
lst match { case 0 :: Nil => "0" case x :: y :: Nil => x + " " + y case 0 :: tail => "0 ..." caes _ => "something else"}
匹配元组
pair match { case (0,_) => "0 ..." case (y,0) => y + " 0" case _ => "neither is 0"}
提取器
提取器带有从对象中提取值的unapply或unapplySeq方法的对象
正则表达式是另一个适合使用提取器的场景,如果正则表达式有分组,可以用提取器来匹配每个分组
var pattern = "([0-9]+ ([a-z]+)".r"99 bottles" match { case pattern( num, item ) => ...}
变量声明中的模式
val ( x, y ) = (1,2)var (q,r) = BigInt(10) /% 3var Array(first, second, _* ) = arr
for表达式中的模式
for( (k,v) <- System.getProperties() ) ...for( (k,v) <- System.getProperties() if v == "" ) ...
样例类
用于模式匹配
abstract class Amount// 扩展自常规类的样例类case class Dollar(value:Double) extends Amountcase class Currency(value:Double, until: String) extends Amount// 针对单例的样例对象case object Nothing extends Amount
// 样例类匹配Amount对象amt match { case Dollar(v) => "$" + v case Currency( _, u ) => u + "$" case Nothing => ""}
copy方法和带名参数
样例类的copy方法创建一个与现有对象值相同的新对象,可修改某些属性
var amt = Currency( 29.95, "EUR")val price = amt.copy(value=19.95, unit="CHF") //
case语句中的中置表示法
如果unapply方法产生一个对偶,则可以在case语句中使用中置表示法,该特性可以用来匹配序列
例如,每个List对象要么是Nil,要么是样例类 ::
case class ::[E]( head: E, tail: List[E] ) extends List[E]
可以写成:
lst match { case h :: t => ... } // 等同于 case ::(h,t),将调用 ::.unapply(lst)
将解析结果组合在一起的 ~ 样例类
result match { case p ~ q => ... }result match { case p ~ q ~ r => ... }
如果操作符以冒号结尾,则是从右向左结合的
case first :: second :: rest // case ::(first, ::(second, rest) )
匹配嵌套结构
abstract class Itemcase class Article( description: String, price: Double ) extends Itemcase class Bubble( description: String, discount: Double, item: Item*) extends ItemBundle("Father's day", 20.0, Article("Scala",39.95) )Bundle("Father's day", 20.0, Article("Scala",39.95), Article("Scala",39.95) )
模式可以匹配到特定的嵌套
case Bundle( _, _, Article(descr,_), _* ) => ... // descr 是第一个 Article 的描述case Bundle( _, _, art @ Article( _, _ ), rest @ _* ) => ... // art 是第一个article, rest是剩余Item的序列case Bundle( _, _, art @ Article( _, _ ), rest => ... // 一个Articel加上一个Item
示例
def price( it: Item ) : Double = it match { case Article( _, p ) => p case Bundle( _, disc, its @ _* ) => its.map( price _ ).sum - disc}
密封类
当用样例类做模式匹配时,你可能想让编译器帮你确保你已经列出了所有可能的选择,要达到这个目的,需要将样例类的通用超类声明为 sealed
sealed abstract class Amount case class Dollar( value: Double ) extends Amountcase class Currency( value: Double, unit: String ) extends Amount
密封类的所有子类都必须在与该密封类相同的文件中定义
如果某个类是密封的,那么在编译期所有子类就是已知的,因而编译器可以检查模式语句的完整性。
模拟枚举
样例类可以让你在Scala中模拟出枚举类型
如果觉得这样的方式有些过重,可以使用之前介绍的Enumeration助手类
sealed abstract class TrafficLightColorcase object Red extends TrafficLightColorcase object Yellow extends TrafficLightColorcase object Green extends TrafficLightColorcolor match { case Red => "stop" case Yellow => "hurry up" case Green => "go"}
Option类型
Option表示可能存在也可能不存在的值, 如样例子类Some包装了某个值Some(“Fred”),而样例对象None表示没有值,这比使用空字符串的意图更加清晰,比使用null来表示缺少某值的做法更加安全。
Option支持泛型,Some(“Fred”) 的类型为 Option[String]
Map类的get方法返回一个Option
scores.get("Alice") match { case Some(score) => println( score ) case None => println( "No score" )}// 等价于:println( scores.getOrElse( "Alice", "No score" ) ) )
如果想略过None值,可以用for推导式
for( score <- scores.get("Alice") ) println( score )scores.get("Alice").foreach( println _ )
如果get方法返回None,什么都不会发生,如果返回Some,则score将被绑定到它的内容
偏函数
被包在花括号内的一组case语句是一个偏函数:一个并非对所有输入值都有定义的函数,它是PartialFunction[A, B]类的一个实例。( A是参数类型,B是返回类型 )
该类有两个方法:apply方法从匹配到的模式计算函数值,而isDefinedAt方法在输入至少匹配其中一个模式时返回true
var f : PartialFunction[Char, Int] = { case '+' => 1; case '-' => -1 }f( '-' ) // 调用 f.apply('-') 返回 -1f.isDefinedAt('0') // falsef('0') // 抛出 MatchError
有一些方法接受PartialFunction作为参数,举例来说,GenTraversable特质的collect方法将一个偏函数应用到所有在该偏函数有定义的元素,并返回包含这些结果的序列
"-3+4".collecct { case '+' => 1; case '-' => -1 } // Vector( -1, 1 )
- 快学Scala笔记(五)
- 快学scala习题(五)
- 快学scala笔记.
- 快学Scala笔记(一)
- 快学Scala笔记(二)
- 快学Scala笔记(三)
- 快学Scala笔记(四)
- 快学scala:笔记1
- 快学scala:笔记2
- 快学scala:笔记3
- 《快学scala》笔记一
- 《快学scala》笔记及章节答案(3)
- 《快学scala》笔记及答案1
- 《快学scala》笔记及答案2
- 快学scala笔记之01-数据类型
- 快学scala笔记之02-类
- 快学scala习题(二)
- 快学scala习题(一)
- 链表算法题技巧总结
- ThreadLocal的设计理念与作用
- C++——NOIP2016普及组 t3——海港
- 安卓源码解析网址
- 大型网站系统架构演化之路
- 快学Scala笔记(五)
- Android layout属性大全
- 人生犹如标题
- Java数组排序-选择排序
- JAVA中的for-each循环与迭代
- vim 配置phpcs phpmd
- 具体mongo 中关于java的各个接口实现方法。
- session的工作原理
- Fiddler查看Https网络请求