Scala学习笔记——case模式匹配

简单匹配

 简单匹配Boolean值

val boolSeq = Seq(true, false)
  for (bool <- boolSeq) {
    bool match {
      case true => println("hi true")
      case false => println("hi false")
    }
  }

match中的值、变量和类型

 匹配特定类型的几个值:

 for {
    x <- Seq(1, 2, 2.7, "one", "two", 'four)
  } {
    val str = x match {
      case 1          => "int 1"
      case i: Int     => "other int : " + i
      case d: Double  => "a double: " + d
      case "one"      => "string one"
      case s: String  => "other string:" + s
      case unexpected => "unexception value :" + unexpected
    }
    println(str)
  }

case _在结尾作为默认子句,用来匹配任意输入值。

for {
    x <- Seq(1, 2, 2.7, "one", "two", 'four)
  } {
    val str = x match {
      case 1          => "int 1"
      case _: Int     => "other int" + x
      case _: Double  => "other double" + x
      case "one"      => "string one"
      case _: String  => "other string:" + x
      case _          => "unexpected value: " + x
    }
    println(str)
  }

  case y 的含义其实就是匹配所有输入(由于这里没有类型注解),并将其赋值给新的变量y.这里的y没有被解释为方法参数y.因此,事实上我们将一个默认的,匹配一切的语句写在了第一个,导致系统给出了这条“变量型匹配语句”会匹配一切输入的警告。代码也从未执行到第二条case语句,于是就得到了两条关于不可达代码的警告

def checkX(y: Int) = {
    for {
      x <- Seq(99, 100, 101)
    } {
      val str = x match {
        case y      => "found y!"
        case i: Int => "int:" + i
      }
      println(str)
    }
  }

  checkX(999)
  println("------------- check y")

输出结果

------------- check x
found y!
found y!
found y!

 case 字句中,以小写字母开头的标识符被认为是用来提取待匹配值的新变量。如果需要引用之前已经定义的变量时,使用反引号将其包围。 于此相对,以大写字母开头的标识符被认为是类型名称:

  def checkY(y: Int) = {
    for {
      x <- Seq(99, 100, 101)
    } {
      val str = x match {
        case `y`    => "found y!"
        case i: Int => "int:" + i
      }
      println(str)
    }
  }

  checkY(99)
------------- check y
found y!
int:100
int:101

 case字句也持“或”逻辑 :|

/**
    * case字句也持“或”逻辑 :|
    */
  for {
    x <- Seq(1, 2, 2.7, "one", "two", 'four)
  } {
    val str = x match {
      case _: Int | _: Double   => "a number: " + x
      case "one"                => "String one"
      case _: String            => "other string:" + x
      case _                    => "unexpected value:" + x
    }
    println(str)
  }


序列的模式匹配

/**
  * 序列的模式匹配
  */

object SeqCaseApp extends App {

  val nonEmptySeq = Seq(1, 2, 3, 4, 5)

  val emptySeq = Seq.empty[Int]

  val nonEmptyList = List(1, 2, 3, 4, 5)

  val emptyList = Nil

  val nonEmptyVector = Vector(1, 2, 3, 4, 5)

  val emptyVector = Vector.empty[Int]

  val nonEmptyMap = Map("one" -> 1, "two" -> 2, "three" -> 3)

  val emptyMap = Map.empty[String, Int]

  //定义了一个递归方法,从Seq[T]中构造String,T为某种待定的类型。方法体是用来与输入的Seq[T]相匹配
  def seqToString[T](seq: Seq[T]): String = seq match {
    case head +: tail => s"$head +: " + seqToString(tail)
    case Nil          => "Nil"
  }

  for (seq <- Seq(nonEmptySeq, emptySeq, nonEmptyList, emptyList, nonEmptyVector, emptyVector, nonEmptyMap.toSeq, emptyMap.toSeq)) {
    println(seqToString(seq))
  }
}

元祖的匹配

 扫描元组的字面量,很容易对元祖进行匹配:

package base.caseT

object TupleCaseApp extends App {

  val langs = Seq(
    ("Scala", "Java", "Clojure"),
    ("Clojure", "Rich", "python")
  )

  for (tuple <- langs) {
    tuple match {
      case ("Scala", _, _)     => println("found scala")
      case (lang, first, last) => println(s"found other language : $lang ($first, $last)")
    }
  }

  // 打印1,2
  (1,2) match {
    case (a,b) => println(a+","+b)
  }

  // 打印2
  (1,2) match {
    case (1, b) => println(b)
  }

  // 打印found
  (1,2) match {
    case (_, 2) => println("found")
  }


  // 得到List(1,2)
  List(1,2,3,4) match {
    case a :: b :: other => List(a, b)
    case _ => List()
  }
  /**
    * guard 语句
    */
  for (i <- Seq(1, 2, 3, 4)) {
    i match {
      case _ if i % 2 == 0 => println(s"even: $i")
      case _               => println(s"odd: $i")
    }
  }

}

case类的匹配

 case类的匹配,可以对case类对象的内容进行考察:

package base.caseT

/**
  * 匹配嵌套类型的内容
  */

object ClassCaseApp extends App {

  case class Address(street: String, city: String, country: String)

  case class Person(name: String, age: Int, address: Address)

  val alice = Person("Alice", 25, Address("101", "杭州", "拱墅区"))
  val bob = Person("Bob", 29, Address("102", "北京", "望京"))
  val marry = Person("Marry", 25, Address("103", "南京", "栖霞区"))

  for(person <- Seq(alice, bob, marry)) {
    person match {
      case Person("Alice", 25, Address(_, "杭州", _))     => println("Hi Alice")
      case Person("Bob", 29, Address(_, "北京", _))       => println("Hi Bob")
      case Person(name, age, _)                          => println(s"who are you, $age year-old person named $name?")
    }
  }
}

case class执行原理

 当一个类被声名为case class的时候,scala会帮助我们做下面几件事情:

  1. 构造器中的参数如果不被声明为var的话,它默认的话是val类型的,但一般不推荐将构造器中的参数声明为var
  2. 自动创建伴生对象,同时在里面给我们实现子apply方法,使得我们在使用的时候可以不直接显示地new对象
  3. 伴生对象中同样会帮我们实现unapply方法,从而可以将case class应用于模式匹配.
  4. 实现自己的toString、hashCode、copy、equals方法 .
     手动创建三个scala脚本。反编译试验下:
package base

 abstract class A
package base

case class B(name:String, age:Int) extends base.A
case object CaseObject extends base.A{

}

执行命令编译脚本:

scalac A.scala
scalac B.scala
scalac CaseObject.scala

case class B反编译如下:

pjx@pjxdeMacBook-Pro:~/program/scala-2.12.5/bin/base$  javap -private B.class
Compiled from "B.scala"
public class base.B extends base.A implements scala.Product,scala.Serializable {
  private final java.lang.String name;
  private final int age;
  public static scala.Option> unapply(base.B);
  //自动生成半生对象
  public static base.B apply(java.lang.String, int);
  public static scala.Function1, base.B> tupled();
  public static scala.Function1> curried();
  public java.lang.String name();
  public int age();
  public base.B copy(java.lang.String, int);
  public java.lang.String copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public base.B(java.lang.String, int);
}

CaseObject反编译如下:

pjx@pjxdeMacBook-Pro:~/program/scala-2.12.5/bin/base$  javap -private ../CaseObject.class
Compiled from "CaseObject.scala"
public final class CaseObject {
  public static java.lang.String toString();
  public static int hashCode();
  public static boolean canEqual(java.lang.Object);
  public static scala.collection.Iterator productIterator();
  public static java.lang.Object productElement(int);
  public static int productArity();
  public static java.lang.String productPrefix();
}


pjx@pjxdeMacBook-Pro:~/program/scala-2.12.5/bin/base$  javap -private ../CaseObject$.class
Compiled from "CaseObject.scala"
public final class CaseObject$ extends base.A implements scala.Product,scala.Serializable {
  public static CaseObject$ MODULE$;
  public static {};
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  private java.lang.Object readResolve();
  private CaseObject$();
}

case objectcase class 不同的是,没有applyunapply方法,这是因为None不需要创建对象及进行内容提取。

你可能感兴趣的:(Scala学习笔记)