Scala中的模式匹配match

xiaoxiao2021-02-28  62

scala中的模式匹配类似与java中的switch语法,但功能比switch更加强大,且能匹配的方式各种各样。

我总结了一下,scala的match的匹配方式有如下几种:

通配模式 常量模式 变量模式 构造器模式 序列模式 元组模式 类型模式

在介绍模式匹配之前,先要介绍一下Scala的样本类,样本类可以在模式匹配中使用,而一般的普通类则不行。

样本类

先来一个样本类的例子:

abstract class Animal case class Dog() extends Animal case class Person(name: String, age: Int) extends Animal

Scala对样本类添加了一些辅助方法: 1、工厂方法

var p = new Dog() var p = Dog()

这两句的作用是一样的。 2、样本类的参数被当成字段进行处理

var p = Person("shadon", 28) p.name p.age

3、默认实现了toString, hashCode和equals方法

由于以上的三点,因此在使用样本类时非常便利。

通配模式:

person match { case Person(name, age) => println("是个人") case _ => println("other") }

匹配person对象,如果是2个参数的则匹配第一个,这个其实是构造器模式,后面会讲到。通配模式的重点在‘_’,表示匹配任意对象。当然通配符‘_’也可以放在类的参数上,用于匹配参数个数,例如:

p match { case Person(_, _) => println("person") case _ => println("other") }

常量模式

def match1(p: Any): Unit = { p match { case 2 => println("number 2") case "hell" => println("string hell") case Nil => println("null") case _ => println("other") } }

常量模式用于匹配常量值,这个好理解。

变量模式

scala认定变量模式的方式比较奇特:用小写字母开头的变量;

def match1(p: Any): String = { val pp = Math.PI p match { case pp => "PI" } }

这里不论传入什么参数,都会被匹配,而且case里面只能使用一个,不然会抛错。如果想将变量模式转变成常量模式只需要增加转义符:`pp`。 思考:这个变量模式我一直想不通,到底有何用途,哪位网友知道请相告知,谢谢!

构造器模式

def match1(p: Any): String = { p match { case Person("shadon", _) => "shadon" case _ => "no" } }

这里匹配第一个参数为“shadon”的Person。

序列模式

def match1(p: Any): String = { p match { case List(9, _, _) => "9 start" case _ => "no" } }

序列模式主要用于匹配像List, Array这样的序列类。使用‘_*’可以匹配零到多个参数。

def match1(p: Any): String = { p match { case List(9, _, _*) => "9 start" case _ => "no" } }

元组模式

def match1(p: Any): String = { p match { case (_, 1) => "(_, 1)" case _ => "no" } }

类型模式

def match1(p: Any): String = { p match { case a: String => "String a = " + a case b: Int => "Int a = " + b case c: Boolean => "boolean c = " + c case _ => "no" } }

注意在类型模式中使用泛型存在类型擦除的问题:

def match1(p: Any): String = { p match { case map: Map[Int, String] => "Map[Int, String]" case _ => "no" } } def main(args: Array[String]): Unit = { println(match1(Map(1 -> 1, 2 -> 1))) }

这里虽然指定了Map[Int, String]类型,但是结果还是能匹配上,这里任意的Map类型都可以匹配成功。泛型擦除如果出现,编译器都会提示警告信息,所以大家看到泛型擦除的警告信息一定要检查一下,以免遗留BUG。在泛型的擦除问题中,数组Array是一个例外,因为数组在Java或Scala中都进行了特殊处理。

def match1(p: Any): String = { p match { case map: List[String] => "List[String]" case _ => "no" } } def main(args: Array[String]): Unit = { println(match1(List(1))) }

这里数组的类型可以正确匹配。

最后介绍一下模式匹配中的变量绑定

变量绑定@

abstract class Animal case class Dog(name: String, age: Int) extends Animal case class Person(name: String, age: Animal) extends Animal object MatchDemo { def match1(p: Any): String = { p match { case Person("shadon", dog @ Dog("dog", _)) => "dog = " + dog case _ => "no" } } def main(args: Array[String]): Unit = { println(match1(Person("shadon", Dog("dog", 1)))) } }

用@符号设置绑定变量,相当于 val dog = Dog(“dog”, _),这样后面就可以使用dog访问Person的第二个参数。

参考资料:

《Scala编程–综合进阶向导》 http://www.scala-lang.org/
转载请注明原文地址: https://www.6miu.com/read-48759.html

最新回复(0)