ITPub博客

首页 > 数据库 > 数据库开发技术 > Scala快速入门-10-模式匹配与样例类

Scala快速入门-10-模式匹配与样例类

原创 数据库开发技术 作者:HelloTech技术派 时间:2018-01-09 08:00:00 0 删除 编辑

知识点

  • mathch表达式是一个更好的switch,不会有穿透到下一个分支的问题

  • 如果没有模式能够匹配,会抛出MatchError,可以用case _ 模式来避免,相当于Java中的default

  • 模式可以包含一个随意定义的条件,称做守卫

  • 可以匹配数组、列表、元组等模式,然后将匹配到不同部分绑定到变量

  • 样例类及密封类的模式匹配

  • 用Option来存放可能存在也可能不存在的值,比null更安全

更好的switch(match case)

  • 与if类似,match也是表达式,而不是语句

  1. object MatchLearn  extends App {

  2.  val ch: Char = '-'

  3.  val sign = ch match {

  4.    case '+' => 1

  5.    case '-' => -1

  6.    case _ => 0

  7.  }

  8.  println("sign " + sign)

  9. }

  10. // 输出

  11. sign -1

  • 与Java的switch不同,Scala模式匹配并不会自动进行到下一个分支,不必在每个分支末尾显示地使用 break语句

  • 与Java的default等效的 case_模式,有这样一个捕获所有模式的方式,如果没有模式匹配到,代码会抛出MatchError

  • 在match表达式中使用任意类型,而不仅仅是数字

  1. import java.awt.Color

  2. /**

  3.  * @author Yezhiwei

  4.  * @date 18/1/8

  5.  */

  6. object MatchLearn  extends App {

  7.  // match 还可以是非数字类型的

  8.  val color = Color.RED

  9.  val c = color match {

  10.    case Color.RED => "red"

  11.    case Color.BLACK => "black"

  12.    case _ => "pink"

  13.  }

  14.  println("color is " + c)

  15. }

  • 在Scala中,可以给模式添加守卫,如匹配所有数字

  1. object MatchLearn  extends App {

  2.  val param = '4'

  3.  val matchResult = param match {

  4.    case '+' => 1

  5.    case '-' => -1

  6.    case _ if Character.isDigit(param) => Character.digit(param, 10)

  7.    case _ => 0

  8.  }

  9.  println("match result " + matchResult)

  10. }

说明:模式总是从上往下进行匹配的,如果带守卫的这个模式不能匹配,则捕获所有的模式(case _)会被用来尝试进行匹配。

  • 如果 case关键字后面跟着一个变量名,那么匹配的表达式会被赋值给那个变量,还可以在守卫中使用变量

  1. object MatchLearn  extends App {

  2.  ...

  3.  val param1 = '4'

  4.  val matchResult1 = param match {

  5.    case '+' => 1

  6.    case '-' => -1

  7.    case ch if Character.isDigit(ch) => Character.digit(ch, 10)

  8.    case _ => 0

  9.  }

  10.  println("match result1 : " + matchResult1)

  11. }

类型模式

  • 可以对表达式的类型进行匹配

  1. object MatchLearn  extends App {

  2.  ...

  3.  def patternType(obj: Any) = obj match {

  4.    case x: Int => x

  5.    case s: String => s

  6.    case _: BigInt => Int.MaxValue

  7.    case _ => 0

  8.  }

  9.  println(patternType(1))

  10.  println(patternType("1"))

  11.  println(patternType(BigInt.apply(10)))

  12.  println(patternType(BigDecimal.apply(10)))

  13. }

  14. // 输出结果:

  15. 1

  16. 1

  17. 2147483647

  18. 0

  • 匹配发生在运行期,JVM中泛型的类型信息会被擦掉,因此,不能用类型来匹配特定的Map类型 casem:Map[String,Int]=>...// no 可以用 casem:Map[_,_]=>...// ok

  • 在Scala中,更倾向于使用模式匹配,而不是isInstanceOf操作符

匹配数组、列表和元组

  • 要匹配数组的内容,可以在模式中使用Array表达式

  1. object MatchLearn  extends App {

  2.  ...

  3.  def patternArray(obj: Array[Any]) = obj match {

  4.    // 匹配包含0的数组

  5.    case Array(0) => "0"

  6.    // 匹配任意两个元素的数组,并将这两个元素分别绑定到x 和 y 变量

  7.    case Array(x, y) => x + " <-> " + y

  8.    // 匹配以0开始的数组

  9.    case Array(0, _*) => "0 ..."

  10.    case _ => "something else"

  11.  }

  12.  println(patternArray(Array(0)))

  13.  println(patternArray(Array(1, 2)))

  14.  println(patternArray(Array(0, 2, 4)))

  15.  println(patternArray(Array(2, 4, 6)))

  16. }

说明:

匹配包含0的数组

匹配任意两个元素的数组,并将这两个元素分别绑定到x 和 y 变量

匹配以0开始的数组

  • 使用List表达式,匹配列表,或者可以使用 ::操作符

  1. object MatchLearn  extends App {

  2.  ...

  3.  def patternList(obj: List[Int]) = obj match {

  4.    // 匹配包含0的List

  5.    case 0 :: Nil => "0"

  6.    // 匹配任意两个元素的List,并将这两个元素分别绑定到x 和 y 变量

  7.    case x :: y :: Nil => x + " <-> " + y

  8.    // 匹配以0开始的List

  9.    case 0 :: tail => "0 ..."

  10.    case _ => "something else"

  11.  }

  12.  println(patternList(List(0)))

  13.  println(patternList(List(1, 2)))

  14.  println(patternList(List(0, 2, 4, 6, 8)))

  15.  println(patternList(List(2, 4, 6, 8)))

  16. }

  • 元组在模式匹配中使用

  1. object MatchLearn  extends App {

  2.  ...

  3.  print("*" * 10)

  4.  print("Tuple")

  5.  println("*" * 10)

  6.  def patternTuple(x: Int, y: Int) = (x, y) match {

  7.    // 匹配包含0的List

  8.    case (0, _) => "0 ... "

  9.    // 匹配任意两个元素的List,并将这两个元素分别绑定到x 和 y 变量

  10.    case (y, 0) => y + " 0 "

  11.    case _ => "tuple something else"

  12.  }

  13.  println(patternTuple(0, 1))

  14.  println(patternTuple(2, 0))

  15.  println(patternTuple(1, 2))

  16. }

  17. // 输出

  18. 0 ...

  19. 2 0

  20. tuple something else

样例类

  • 样例类是一种特殊类,它们常用于模式匹配

  1. object CaseClassLearn extends App {

  2.  def patternAmount(amount: Amount) = amount match {

  3.      case Dollar(v) => "$" + v

  4.      case Currency(v, u) => "I got " + v + " " + u

  5.      case Nothing => "Nothing"

  6.      case _ => ""

  7.  }

  8.  println(patternAmount(Dollar(1.0)))

  9.  println(patternAmount(Currency(1.0, "RMB")))

  10.  println(patternAmount(Nothing))

  11. }

  12. abstract class Amount

  13. case class Dollar(value: Double) extends Amount

  14. case class Currency(value: Double, unit: String) extends Amount

  15. // 样例对象

  16. case object Nothing extends Amount

  17. // 输出

  18. $1.0

  19. I got 1.0 RMB

  20. Nothing

说明:

样例类的实例使用(), 样例对象不使用圆括号()

声明样例类时,构造器中的每一个参数都成为val

在伴生对象中提供apply方法,让你不用new关键字就能构造出相应的对象,如: Dollar(1.0)

提供unapply方法让模式匹配可以工作

将生成 toString,equals,hashCode,copy方法

密封类(sealed样例类)

  • 当用样例类来做模式匹配时,你可能想让编译器帮你确保你已经列了所有的可能选择,要达到这个目的,需要将样例类的通用超类声明为 sealed

  • 密封类的所有子类都必须在与该密封类相同的文件中定义

  • 如果某个类是密封的,那么在编译期所有子类就是可知的,因而编译器可以检查模式语句的完整性,让同一组样例类都扩展某个密封的类或特质是个好的做法

在上面示例的基本上增加一下 sealed abstract class Amount,然后注释掉一个 case 重新编译试一试

Option类型

  • 标准类库中的Option类型用样例类来表示可能存在、也可能不存在的值

  • 子类Some包装了某个值,如 Some("Fred"),None表示没有值,比使用空字符串的意图列加清晰,比使用null来表示缺少的某值的做法更加安全

  • 也可以通过模式匹配来输出匹配值

  1. object OptionLearn extends App {

  2.  val site: Map[String, String] = Map("baidu" -> "", "google" -> "")

  3.  val value1 = site.get("Yezhiwei")

  4.  val value2: Option[String] = site.get("Yezhiwei")

  5.  val value3: Option[String] = site.get("baidu")

  6.  println("value1 " + value1)

  7.  println("value2 " + value2)

  8.  println("value3 " + value3)

  9.  println()

  10.  println("show value2 " + show(value2))

  11.  println("show value3 " + show(value3))

  12.  def show(v: Option[String]) = v match {

  13.    case Some(v) => v

  14.    case None => "?"

  15.  }

  16. }

  17. // 输出

  18. value1 None

  19. value2 None

  20. value3 Some(www.baidu.com)

  21. show value2 ?

  22. show value3 www.baidu.com


敬请期待下一篇<常用集合操作>~


原文作者:HelloTech技术派;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2017-12-05

  • 博文量
    181
  • 访问量
    73724