scala的模式匹配,关键字是match,类似于java的switch,但是功能更强大,我们看看scala模式匹配的几种类型。

常量匹配

我们这里以字符串为例。关键字是match,case后面通过=>来分隔匹配的模式以及匹配后的代码。
case是各个分支,如果匹配成功,就会执行相应的代码块,这里的代码块可以不用大括号。如果都不匹配,那旧执行case _里的代码块,相对于java的default。

val str: String = "b"
val result = str match {
  case "a" => 1
  case "b" => println("b")
    2
  case "c" => 3
  case _ => 0
}
println(result)  // 2

如果case b部分改以下代码,由于if里的条件不符合,那他会到case _ ,返回0。

case "b" if(str.equals("c"))  => println("b")

类型匹配

与上面稍微有点不同的是,类型前面要加一个参数,这个参数可以在后面的代码块里可以引用。

def main(args: Array[String]): Unit = {
    val array: Array[Any] = Array("a", 1, true, Array(1))
    for (e <- array) {
      matchCase(e)
    }
}

def matchCase(v: Any): Unit = {
    v match {
      case a: Int => println(s"Int $a")
      case b: String => println(s"String $b")
      case c: Boolean => println(s"Boolean $c")
      case _ => println(s"Nothing")
    }
}

运行结果如下:

String a
Int 1
Boolean true
Nothing

数组匹配

def main(args: Array[String]): Unit = {
    val array: Array[Array[Int]] = Array(Array(1), Array(0, 1), Array(1, 2), Array(1, 2, 3), Array(2, 3, 4))
    for (e <- array) {
      matchArray(e)
    }
}

def matchArray(v: Array[Int]): Unit = {
    v match {
      // 匹配Array(1)
      case Array(1) => println(v(0))
      // 匹配两个长度的数组
      case Array(x, y) => println("x+y=" + (x + y))
      // 匹配第一个元素为1,长度不限制的数组
      case Array(1, _*) => println("x")
      case _ => println(s"Nothing")
    }
}

运行结果如下:

1
x+y=1
x+y=3
x
Nothing

元组匹配

def main(args: Array[String]): Unit = {
    val array: Array[Any] = Array((1, 2), (2, 1), (3, 4), (1, 2, 3))
    for (e <- array) {
      matchTuple(e)
    }
  }

def matchTuple(v: Any): Unit = {
    v match {
      // 匹配1结尾
      case (x, 1) => println(x)
      // 匹配1开头
      case (1, y) => println(y)
      // 匹配两个长度的元祖
      case (x, y) => println(s"x = $x, y = $y")
      case _ => println(s"Nothing")
    }
}

运行结果如下:

2
2
x = 3, y = 4
Nothing

集合匹配

下面注释掉的部分代码等同于他的下一句。

def main(args: Array[String]): Unit = {
    val list: List[List[Int]] = List(List(0), List(1), List(1, 2), List(1, 2, 3))
    for (e <- list) {
      matchList(e)
    }
  }

def matchList(v: List[Int]): Unit = {
    v match {
      // 匹配List(1)
      // case List(1) => println(v(0))
      case 1 :: Nil => println(v(0))
      // 匹配两个长度的数组
      // case List(x, y) => println("x+y=" + (x + y))
      case x :: y :: Nil => println("x+y=" + (x + y))
      // 匹配第一个元素为1,长度不限制的数组
      // case List(1, _*) => println(v(0) + "-" + v.tail)
      case x :: tail => println(x + "-" + tail)
      case _ => println(s"Nothing")
}

运行结果如下:

0-List()
1
x+y=3
1-List(2, 3)

对象匹配

对象匹配是匹配对象的值,但是case里仅仅调用Person伴生对象的apply方法创建一个对象是不行的,他还需要Person的伴生对象声明unapply方法。
case中对比的时候,他会把Person对象传入到unapply方法,得到Some,然后再根据对象的属性进行匹配。

def main(args: Array[String]): Unit = {
    val list: List[Person] = List(Person("张三", 18), Person("李四", 20), Person("王五", 28))
    for (e <- list) {
      matchPerson(e)
    }
  }

def matchPerson(v: Person): Unit = {
    v match {
      case Person("张三", 18) => println(s"姓名:${v.name},年龄:${v.age}")
      case Person("李四", 20) => println(s"姓名:${v.name},年龄:${v.age}")
      case _ => println(s"Nothing")
    }
}

class Person(val name: String, val age: Int) {

}

object Person {
  def apply(name: String, age: Int): Person = new Person(name, age)

  def unapply(person: Person): Option[(String, Int)] = {
    if (null == person) {
      None
    } else {
      Some(person.name, person.age)
    }
  }
}

样例类

如果每次对象都要像上面进行匹配,那代码就很繁琐了。
所以scala提供了一个样例类,关键字case,上面的代码可以简化成下面的:

def main(args: Array[String]): Unit = {
    val list: List[Person2] = List(Person2("张三", 18), Person2("李四", 20), Person2("王五", 28))
    for (e <- list) {
      matchPerson(e)
    }
 }

def matchPerson(v: Person2): Unit = {
    v match {
      case Person2("张三", 18) => println(s"姓名:${v.name},年龄:${v.age}")
      case Person2("李四", 20) => println(s"姓名:${v.name},年龄:${v.age}")
      case _ => println(s"Nothing")
    }
}


case class Person2(name: String, age: Int)

通过case关键字,Person2的对象就自动生成伴生对象,并且伴生对象除了生成上面的apply和unapply方法以外,还生成了toString、equals、hashCode 和 copy这些方法。如果作用在class上,那这个class就是多例的,如果作用在object上,那就是单例的。
我们可以看到构造函数并没有指定val还是var的,他默认是val的。


大军
847 声望183 粉丝

学而不思则罔,思而不学则殆


« 上一篇
Scala - 映射

引用和评论

0 条评论