提取器 模式匹配
提取器效果與構造器相反:構造器從給定的參宿列表創建一個對象,而提取器卻是從傳遞給它的對象中提取出構造該對象的參數
樣例類
scala自動為樣例類創建一個伴生對象:一個包含了apply
和unappley
方法的單例對象
apply
方法用來創建樣例類的實例,unapply
需要被伴生對象實現,以使其成為提取器
第一個提取器
trait User {
def name:String
}
class FreeUser(val name:String) extends User
class PremiumUser(val name:String) extends User
object FreeUser {
def unapply(user:FreeUser):Option[String] = Some(user, name)
}
object PremiumUser {
def unapply(user:PremiumUser):Option[String] = Some(user, name)
}
//test code
val user:User = new PremiumUser("Daniel")
user match {
case FreeUser(name) => "Hello, " + name
case PremiumUser(name) => "Welcome back, " + name
}
提取多個值
trait User {
def name:String
def score:Int
}
class FreeUser(
val name:String,
val score:Int,
val upgradeProbability:Double
) extends User
class PremiumUser(
val name:String,
val score:Int
) extends User
object FreeUser {
def unapply(user:FreeUser):Option[(String, Int, Double)] = Some((user.name, user.score, user.upgradeProbability))
}
object PremiumUser {
def unapply(user:PremiumUser):Option[(String, Int)] = Some((user.name, user.score))
}
//test code
val user:User = new FreeUser("Daniel", 3000, 0.7d)
user match {
case FreeUser(name, _, p) =>
if (p > 0.75) "$name, what can we do for you today?"
else "Hello $name"
case PremiumUser(name, _) => "Welcome back, dear $name"
}
布爾提取器
用于檢查是否匹配
object premiumCandidate {
def unapply(user:FreeUser):Boolean = user.upgradeProbability > 0.75
}
//test code
val user:User = new FreeUser("Daniel", 2500, 0.8d)
user match {
case freeUser @ premiumCandidate() => initiateSpamProgram(freeUser)
case _ => sendRegularNewsletter(user)
}
-
@
操作符
將提取器匹配成功的實例綁定到一個變量上,該變量有著與提取器所接受的對象相同的類型
中綴表達式
val xs = 58 #:: 43 #:: 93 #:: Stream.empty
xs match {
case first #:: second #:: _ => first - second
case _ => -1
}
- 結構列表、流的方法與創建方法類似,都使用cons操作符
cons操作符:::
,#::
- 列表和流的cons操作符一般使用中綴表達式
流提取器
object #:: {
def unapply[A](xs: Stream[A]):Option[(A, Stream[A])] =
if (xs.isEmpty) None
else Some(xs.head, xs.tail)
}
使用提取器
- 使用樣例類自動獲得可用的提取器
- 只有當從無法掌控的類型中提取數據,或者是需要其他進行模式匹配的方法時,才需要實現自己的提取器
提取器的一種常見用法是從字符串中提取出有意義的值
序列提取
scala提供了提取任意多個參數的模式匹配方法
接受某一類型的對象,將其解構成列表
提取給定的名字
object GivenNames {
def unapplySeq(name:String):Option[Seq[String]] = {
val names = name.trim.split(" ")
if (name.forall(_.isEmpty)) None
else Some(names)
}
}
def greetWithFirstName(name:String) = name match {
case GivenNames(firstName, _*) => "Good morning, $firstName"
case _ => "Welcome! Please make sure to fill in your name"
}
固定和可變的參數提取
object Names {
def unapplySeq(name:String):Option[(String, String, Seq[String])] = {
val names = name.trim.split(" ")
if (names.size < 2) None
else Some((names.last, names.head, names.drop(1).dropRight(1)))
}
}
def greet(fullName:String) = fullName match {
case Names(lastName, firstName, _*) =>
"Good morning, $firstName $lastName!"
case _ =>
"Welcome! Please make sure to fill in your name"
}
無處不在的模式
模式匹配表達式
模式匹配表達式:其返回值是由第一個匹配的模式中的代碼塊決定的
模式匹配允許解耦兩個并不真正屬于彼此的東西,使得代碼易于測試
值定義中的模式
def gameResult():(String, Int) = ("Daniel", 3500)
val result = gameResult()
println(result._1 + ":" + result._2)
val (name, score) = gameResult()
println()