簡單匹配
簡單匹配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會幫助我們做下面幾件事情:
- 構造器中的參數如果不被聲明爲var的話,它默認的話是val類型的,但一般不推薦將構造器中的參數聲明爲var
- 自動創建伴生對象,同時在裏面給我們實現子apply方法,使得我們在使用的時候可以不直接顯示地new對象
- 伴生對象中同樣會幫我們實現unapply方法,從而可以將case class應用於模式匹配.
- 實現自己的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<scala.Tuple2<java.lang.String, java.lang.Object>> unapply(base.B);
//自動生成半生對象
public static base.B apply(java.lang.String, int);
public static scala.Function1<scala.Tuple2<java.lang.String, java.lang.Object>, base.B> tupled();
public static scala.Function1<java.lang.String, scala.Function1<java.lang.Object, base.B>> 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<java.lang.Object> 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<java.lang.Object> 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<java.lang.Object> productIterator();
public boolean canEqual(java.lang.Object);
public int hashCode();
public java.lang.String toString();
private java.lang.Object readResolve();
private CaseObject$();
}
case object
與case class
不同的是,沒有apply
和unapply
方法,這是因爲None
不需要創建對象及進行內容提取。