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

简介: mathch表达式是一个更好的switch,不会有穿透到下一个分支的问题如果没有模式能够匹配,会抛出MatchError,可以用case _ 模式来避免,相当于Java中的default模式可以包含一个随意定义的条件,称做守卫可以匹配数组、列表、元组等模式,然后将匹配到不同部分绑定到变量样例类及密封类的模式匹配用Option来存放可能存在也可能不存在的值,比null更安全

知识点


  • mathch表达式是一个更好的switch,不会有穿透到下一个分支的问题
  • 如果没有模式能够匹配,会抛出MatchError,可以用case _ 模式来避免,相当于Java中的default
  • 模式可以包含一个随意定义的条件,称做守卫
  • 可以匹配数组、列表、元组等模式,然后将匹配到不同部分绑定到变量
  • 样例类及密封类的模式匹配
  • 用Option来存放可能存在也可能不存在的值,比null更安全

更好的switch(match case)


  • 与if类似,match也是表达式,而不是语句
object MatchLearn  extends App {
  val ch: Char = '-'
  val sign = ch match {
    case '+' => 1
    case '-' => -1
    case _ => 0
  }
  println("sign " + sign)
}
// 输出
sign -1
  • 与Java的switch不同,Scala模式匹配并不会自动进行到下一个分支,不必在每个分支末尾显示地使用 break语句
  • 与Java的default等效的 case_模式,有这样一个捕获所有模式的方式,如果没有模式匹配到,代码会抛出MatchError
  • 在match表达式中使用任意类型,而不仅仅是数字
import java.awt.Color
/**
  * @author Yezhiwei
  * @date 18/1/8
  */
object MatchLearn  extends App {
  // match 还可以是非数字类型的
  val color = Color.RED
  val c = color match {
    case Color.RED => "red"
    case Color.BLACK => "black"
    case _ => "pink"
  }
  println("color is " + c)
}
  • 在Scala中,可以给模式添加守卫,如匹配所有数字
object MatchLearn  extends App {
  val param = '4'
  val matchResult = param match {
    case '+' => 1
    case '-' => -1
    case _ if Character.isDigit(param) => Character.digit(param, 10)
    case _ => 0
  }
  println("match result " + matchResult)
}

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

  • 如果 case关键字后面跟着一个变量名,那么匹配的表达式会被赋值给那个变量,还可以在守卫中使用变量
object MatchLearn  extends App {
  ...
  val param1 = '4'
  val matchResult1 = param match {
    case '+' => 1
    case '-' => -1
    case ch if Character.isDigit(ch) => Character.digit(ch, 10)
    case _ => 0
  }
  println("match result1 : " + matchResult1)
}

类型模式


  • 可以对表达式的类型进行匹配
object MatchLearn  extends App {
  ... 
  def patternType(obj: Any) = obj match {
    case x: Int => x
    case s: String => s
    case _: BigInt => Int.MaxValue
    case _ => 0
  }
  println(patternType(1))
  println(patternType("1"))
  println(patternType(BigInt.apply(10)))
  println(patternType(BigDecimal.apply(10)))
}
// 输出结果:
1
1
2147483647
0
  • 匹配发生在运行期,JVM中泛型的类型信息会被擦掉,因此,不能用类型来匹配特定的Map类型 casem:Map[String,Int]=>...// no 可以用 casem:Map[_,_]=>...// ok
  • 在Scala中,更倾向于使用模式匹配,而不是isInstanceOf操作符

匹配数组、列表和元组


  • 要匹配数组的内容,可以在模式中使用Array表达式
object MatchLearn  extends App {
  ...
  def patternArray(obj: Array[Any]) = obj match {
    // 匹配包含0的数组
    case Array(0) => "0"
    // 匹配任意两个元素的数组,并将这两个元素分别绑定到x 和 y 变量
    case Array(x, y) => x + " <-> " + y
    // 匹配以0开始的数组
    case Array(0, _*) => "0 ..."
    case _ => "something else"
  }
  println(patternArray(Array(0)))
  println(patternArray(Array(1, 2)))
  println(patternArray(Array(0, 2, 4)))
  println(patternArray(Array(2, 4, 6)))
}

说明:

匹配包含0的数组

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

匹配以0开始的数组

  • 使用List表达式,匹配列表,或者可以使用 ::操作符
1. object MatchLearn  extends App {
2. 
3.   ...
4.   def patternList(obj: List[Int]) = obj match {
5.     // 匹配包含0的List
6.     case 0 :: Nil => "0"
7.     // 匹配任意两个元素的List,并将这两个元素分别绑定到x 和 y 变量
8.     case x :: y :: Nil => x + " <-> " + y
9.     // 匹配以0开始的List
10.     case 0 :: tail => "0 ..."
11.     case _ => "something else"
12.   }
13. 
14.   println(patternList(List(0)))
15.   println(patternList(List(1, 2)))
16.   println(patternList(List(0, 2, 4, 6, 8)))
17.   println(patternList(List(2, 4, 6, 8)))
18. }
• 元组在模式匹配中使用
19. object MatchLearn  extends App {
20. 
21.   ...
22.   print("*" * 10)
23.   print("Tuple")
24.   println("*" * 10)
25.   def patternTuple(x: Int, y: Int) = (x, y) match {
26.     // 匹配包含0的List
27.     case (0, _) => "0 ... "
28.     // 匹配任意两个元素的List,并将这两个元素分别绑定到x 和 y 变量
29.     case (y, 0) => y + " 0 "
30.     case _ => "tuple something else"
31.   }
32. 
33.   println(patternTuple(0, 1))
34.   println(patternTuple(2, 0))
35.   println(patternTuple(1, 2))
36. }
37. 
38. // 输出
39. 0 ... 
40. 2 0 
41. tuple something else

样例类


  • 样例类是一种特殊类,它们常用于模式匹配
object CaseClassLearn extends App {
  def patternAmount(amount: Amount) = amount match {
      case Dollar(v) => "$" + v
      case Currency(v, u) => "I got " + v + " " + u
      case Nothing => "Nothing"
      case _ => ""
  }
  println(patternAmount(Dollar(1.0)))
  println(patternAmount(Currency(1.0, "RMB")))
  println(patternAmount(Nothing))
}
abstract class Amount
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
// 样例对象
case object Nothing extends Amount
// 输出
$1.0
I got 1.0 RMB
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来表示缺少的某值的做法更加安全
  • 也可以通过模式匹配来输出匹配值
object OptionLearn extends App {
  val site: Map[String, String] = Map("baidu" -> "www.baidu.com", "google" -> "www.google.com")
  val value1 = site.get("Yezhiwei")
  val value2: Option[String] = site.get("Yezhiwei")
  val value3: Option[String] = site.get("baidu")
  println("value1 " + value1)
  println("value2 " + value2)
  println("value3 " + value3)
  println()
  println("show value2 " + show(value2))
  println("show value3 " + show(value3))
  def show(v: Option[String]) = v match {
    case Some(v) => v
    case None => "?"
  }
}
// 输出
value1 None
value2 None
value3 Some(www.baidu.com)
show value2 ?
show value3 www.baidu.com
相关文章
|
Scala
166 Scala 模式匹配和样例类
166 Scala 模式匹配和样例类
80 0
|
4月前
|
Scala 开发者
Scala中的模式匹配与高阶函数:探索强大的编程范式
【7月更文挑战第11天】Scala中的模式匹配和高阶函数是两种极其强大的特性,它们不仅提升了代码的表达力和可读性,还使得开发者能够编写出更加灵活和可重用的解决方案。通过
|
5月前
|
Scala
scala-模式匹配(字符串、数组、元组、集合、类、偏函数)
scala-模式匹配(字符串、数组、元组、集合、类、偏函数)
25 0
|
5月前
|
Java 大数据 Scala
Scala快速入门--Scala环境搭建【Windows10】图解
Scala快速入门--Scala环境搭建【Windows10】图解
60 0
|
6月前
|
Scala
Scala中的异常处理和模式匹配
Scala中的异常处理和模式匹配
43 1
|
6月前
|
Scala
Scala中的模式匹配:强大的匹配和转换工具
Scala中的模式匹配:强大的匹配和转换工具
42 1
|
6月前
|
Scala
Scala中的类和对象:定义、创建和使用
Scala中的类和对象:定义、创建和使用
149 1
|
6月前
|
分布式计算 Java 大数据
Scala:样例类、模式匹配、Option、偏函数、泛型(三)
Scala:样例类、模式匹配、Option、偏函数、泛型(三)
72 0
|
Scala
163 Scala 类
163 Scala 类
35 0
|
Java Scala
Scala入门到精通——第六节:类和对象(一)
本节主要内容 1 类定义、创建对象 2 主构造器 3 辅助构造器 类定义、创建对象 //采用关键字class定义 class Person { //类成员必须初始化,否则会报错 //这里定义的是一个公有成员 var name:String=null } Person类在编译后会生成Person.class文件 利用javap -prviate P
3901 0