一 apply & unapply方法
apply方法我们已经非常熟悉了,它帮助我们无需new操作就可以创建对象,而unapply方法则用于析构出对象,在模式匹配中特别提到,如果一个类要能够应用于模式匹配当中,必须将类声明为case class,因为一旦被定义为case class,scala会自动帮我们生成相应的方法,这些方法中就包括apply方法及unapply方法。本节将从提取器(也称析构器)的角度对unapply方法进行介绍。先看下面的这个例子:
class Person(val firstName:String,val secondName:String)
//在伴生对象中定义apply方法和unapply方法
object Person{
def apply(firstName: String, secondName: String) = new Person(firstName,secondName)
def unapply(p: Person):Option[(String,String)] = {
if (p != null) Some(p.firstName, p.secondName)
else None
}
}
object ExtractorClient extends App{
val p=Person("nicky","zhang")
p match {
//析构出firstName,secondeName
case Person(firstName,secondName) => println("firstName="+firstName+" secondName="+secondName)
case _ => println("null object")
}
}
二 零变量或者单个变量的绑定模式匹配
前面的例子给定的是模式匹配两个变量,他可以扩展到任意维度,比如:
//Twice用于匹配重复出现的字符串,它绑定的是一个变量
//即返回的类型是Option[String]
object Twice {
def apply(s: String): String = s + s
def unapply(s: String): Option[String] = {
val length = s.length / 2
val half = s.substring(0, length)
if (half == s.substring(length)) Some(half) else None
}
}
//未绑定任何变量,仅仅返回Boolean类型
object UpperCase {
def unapply(s: String): Boolean = s.toUpperCase == s
}
object NonAndOneVariablePattern extends App{
def userTwiceUpper(s: String) = s match {
//下面的代码相当于执行了下面这条语句
//UpperCase.unapply(Twich.unapply(EMail.unapply(s)))
case EMail(Twice(x @ UpperCase()), domain) =>
"match: " + x + " in domain " + domain
case _ =>
"no match"
}
val email=EMail("摇摆少年梦摇摆少年梦","sina.com")
println(userTwiceUpper(email))
}
代码中的EMail(Twice(x @UpperCase()),其执行顺序是先调用EMail的unapply方法,然后再调用Twice中的unapply方法,最后调用UpperCase的unapply方法,如果返回true,则将Twice 中返回的字符串赋值给x。
三 Scala中占位符总结
1、存在性类型:Existential types
def foo(l: List[Option[_]]) = ...
2、高阶类型参数:Higher kinded type parameters
case class A[K[_],T](a: K[T])
3、临时变量:Ignored variables
val _ = 5
4、临时参数:Ignored parameters
List(1, 2, 3) foreach { _ =>println("Hi") }
5、通配模式:Wildcard patterns
Some(5) match { case Some(_) =>println("Yes") }
match {
caseList(1,_,_) => " a list with three element and the first element is1"
caseList(_*) => " a list with zeroor more elements "
caseMap[_,_] => " matches a map with any key type and any value type "
case _=>
}
val (a, _) = (1, 2)
for (_ <- 1 to 10)
6、通配导入:Wildcard imports
import java.util._
7、隐藏导入:Hiding imports
// Imports all the members of the object Fun butrenames Foo to Bar
import com.test.Fun.{ Foo => Bar , _ }
// Imports all the members except Foo. To exclude amember rename it to _
import com.test.Fun.{ Foo => _ , _ }
8、连接字母和标点符号:Joining letters to punctuation
def bang_!(x: Int) = 5
9、占位符语法:Placeholder syntax
List(1, 2, 3) map (_ + 2)
_ + _
( (_: Int) + (_: Int) )(2,3)
val nums = List(1,2,3,4,5,6,7,8,9,10)
nums map (_ + 2)
nums sortWith(_>_)
nums filter (_ % 2 == 0)
nums reduceLeft(_+_)
nums reduce (_ + _)
nums reduceLeft(_ max _)
nums.exists(_ > 5)
nums.takeWhile(_ < 8)
10、偏应用函数:Partially applied functions
def fun = {
// Somecode
}
val funLike = fun _
List(1, 2, 3) foreach println _
1 to 5 map (10 * _)
//List("foo", "bar","baz").map(_.toUpperCase())
List("foo", "bar","baz").map(n => n.toUpperCase())
11、初始化默认值:default value
var i: Int = _
12、作为参数名:
//访问map
var m3 = Map((1,100), (2,200))
for(e<-m3) println(e._1 + ": " + e._2)
m3 filter (e=>e._1>1)
m3 filterKeys (_>1)
m3.map(e=>(e._1*10, e._2))
m3 map (e=>e._2)
//访问元组:tuple getters
(1,2)._2
13、参数序列:parameters Sequence
_*作为一个整体,告诉编译器你希望将某个参数当作参数序列处理。例如val s = sum(1 to 5:_*)就是将1 to 5当作参数序列处理。
//Range转换为List
List(1 to 5:_*)
//Range转换为Vector
Vector(1 to 5: _*)
//可变参数中
def capitalizeAll(args: String*) = {
args.map {arg =>
arg.capitalize
}
}
val arr = Array("what's", "up","doc?")
capitalizeAll(arr: _*)