本节主要内容

  1. apply与unapply方法
  2. 零变量或变量的模式匹配
  3. 提取器与序列模式
  4. scala中的占位符使用总结

1. apply与unapply方法

apply方法我们已经非常熟悉了,它帮助我们无需new操作就可以创建对象,而unapply方法则用于析构出对象,在模式匹配中特别提到,如果一个类要能够应用于模式匹配当中,必须将类声明为case class,因为一旦被定义为case class,Scala会自动帮我们生成相应的方法,这些方法中就包括apply方法及unapply方法。本节将从提取器(也称析构器)的角度对unapply方法进行介绍。先看下面的这个例子(来源于programmin in scala)

object EMail{//apply方法用于无new构造对象def apply(user: String, domain: String) = user + "@" + domain//unapply方法用于在模式匹配中充当extractordef unapply(str: String): Option[(String, String)] = {val parts = str split "@"if (parts.length == 2) Some(parts(0), parts(1)) else None}
}
object ApplyAndUnapply {val email=EMail("zhouzhihubeyond","sina.com")//下面的匹配会导致调用EMail.unapply(email)case EMail(user,domain) => println("user="+user+" domain="+domain)}
}
  • 1

在上述的代码中,我们将unapply方法定义为:
def unapply(str: String): Option[(String, String)] = {
val parts = str split "@"
if (parts.length == 2) Some(parts(0), parts(1)) else None
}

这是有道理的,原因在于可能会有不合法的email用于模式匹配,例如:

object ApplyAndUnapply extends App{def patternMatching(x:String)=x match {//下面的匹配会导致调用EMail.unapply(email)case EMail(user,domain) => println("user="+user+" domain="+domain)//匹配非法邮箱case _ => println("non illegal email")}val email=EMail("zhouzhihubeyond","sina.com")patternMatching(email) patternMatching("摇摆少年梦")
}

从构造与析构的角度来看,apply方法也被称为injection(注入),unapply方法也被称为提取器,这两个方法就像孪生兄弟一样,经常在类或对象中被定义。以前我们在用类进行模式匹配的时候都必须要将类声明为case class,今天我们将不通过case class,而是定义一个普通的类实现自己的apply和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(person: Person):Option[(String,String)]={if(person!=null) Some(person.firstName,person.secondName)else None}
}val p=Person("摇摆少年梦","周")p match {//析构出firstName,secondeNamecase Person(firstName,secondName) => println("firstName="+firstName+" secondName="+secondName)case _ => println("null object")}

2. 零变量或单变量绑定的模式匹配

上一节讲的模式模式匹配绑定的是两个变量,它可以扩展到任意变量维度,这一节中我们对零变量和单个变量绑定的特殊情况进行介绍,我们来看下面的这个例子,该例子来源于 programmin in scala

//Twice用于匹配重复出现的字符串,它绑定的是一个变量
//即返回的类型是Option[String]
object Twice {def apply(s: String): String = s + sdef unapply(s: String): Option[String] = {val length = s.length / 2val 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 " + domaincase _ =>"no match"}val email=EMail("摇摆少年梦摇摆少年梦","sina.com")println(userTwiceUpper(email))
}

代码中的EMail(Twice(x @ UpperCase()),其执行顺序是先调用EMail的unapply方法,然后再调用Twice中的unapply方法,最后调用UpperCase的unapply方法,如果返回true,则将Twice 中返回的字符串赋值给x。

3. 提取器与序列模式

List伴生对象具有下列定义形式:

object List {
def apply[T](elems: T*) = elems.toList
def unapplySeq[T](x: List[T]): Option[Seq[T]] = Some(x)
...
}

从上面的代码来看,与一般的提取器不同的是,序列模式采用unapplySeq代替unapply方法,并且返回的类型是Option[Seq[T]] ,在讲模式匹配的时候我们提到过,序列模式中的匹配经常会使用占位符_或_*的方式匹配序列中的其它元素,这种方式为序列模式所独有,例如:

object ExtractorSequence extends App{val list=List(List(1,2,3),List(2,3,4))list match {//_*表示匹配列表中的其它元素case List(List(one,two,three),_*) => println("one="+one+" two="+two+" three="+three)case _ => println("Other")}list match {//_表示匹配列表中的第一个元素//_*表示匹配List中的其它多个元素//这里采用的变量绑定的方式case List(_,x@List(_*),_*) => println(x)case _ => println("other list")}
}

4. scala中的占位符使用总结

scala作为一种函数式编程语言,有很多地方会让初学者觉得困惑,其中占位符_的使用理解有一定的难度,本节将对其使用进行总结,本小节内容来源http://my.oschina.net/leejun2005/blog/405305,感谢作者的无私奉献。

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 _ = 54、临时参数:Ignored parameters
List(1, 2, 3) foreach { _ => println("Hi") }5、通配模式:Wildcard patterns
Some(5) match { case Some(_) => println("Yes") }
match {case List(1,_,_) => " a list with three element and the first element is 1"case List(_*)  => " a list with zero or more elements "case Map[_,_] => " 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 but renames Foo to Bar
import com.test.Fun.{ Foo => Bar , _ }// Imports all the members except Foo. To exclude a member rename it to _
import com.test.Fun.{ Foo => _ , _ }8、连接字母和标点符号:Joining letters to punctuation
def bang_!(x: Int) = 59、占位符语法: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 = {// Some code
}
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)._213、参数序列: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: _*)

Scala入门到精通——第二十五节 提取器(Extractor)相关推荐

  1. Scala入门到精通——第二十六节 Scala并发编程基础

    本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 1. Scala并发编程简介 2003 年,Herb Sutte ...

  2. Scala入门到精通——第十五节 Case Class与模式匹配(二)

    本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{def main(args: Arra ...

  3. Scala入门到精通——第二十九节 Scala数据库编程

    本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...

  4. Scala入门到精通——第二十四节 高级类型 (三)

    本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在Scala中,类(class)与类型(type)是两个不一样的概念. ...

  5. Scala入门到精通——第十四节 Case Class与模式匹配(一)

    本节主要内容 模式匹配入门 Case Class简介 Case Class进阶 1. 模式匹配入门 在Java语言中存在switch语句,例如: //下面的代码演示了java中switch语句的使用 ...

  6. Scala入门到精通——第二十节 类型参数(二)

    本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对Scala中的 ...

  7. Scala入门到精通——第十九节 隐式转换与隐式参数(二)

    本节主要内容 隐式参数中的隐式转换 函数中隐式参数使用概要 隐式转换问题梳理 1. 隐式参数中的隐式转换 前一讲中,我们提到函数中如果存在隐式参数,在使用该函数的时候如果不给定对应的参数,则编译器会自 ...

  8. Scala入门到精通——第二十八节 Scala与JAVA互操作

    本节主要内容 JAVA中调用Scala类 Scala中调用JAVA类 Scala类型参数与JAVA泛型互操作 Scala与Java间的异常处理互操作 1. JAVA中调用Scala类 Java可以直接 ...

  9. Scala入门到精通——第二十三节 高级类型 (二)

    本节主要内容 中置类型(Infix Type) 存在类型 函数类型 抽象类型 关于语法糖的问题,在讲解程序语言时,我们常常听到"语法糖"这个术语,在百度百科中,它具有如下定义: 语 ...

最新文章

  1. docker容器内部无法ping通域名?
  2. python绘制散点图的函数_python绘制散点图
  3. Linux系统编程 -- exec函数族
  4. 【HTML5】页面传递参数给下一个页面
  5. (Oracle)数据量统计存储过程
  6. python返回类型为anytype_python - Zeep的SOAP请求(Python) - 堆栈内存溢出
  7. 在心中刻上你的名字,让思念如烟
  8. 网易云信 NIM_duilib 源码分析
  9. SIMPLE、PISO 、PIMPLE算法浅析
  10. CSDN博客调整图片大小
  11. Vue SPA项目SEO优化之预渲染Prerender-spa-plugin
  12. Eclipse Memory Analyzer 使用技巧
  13. 【Python爬虫】Python+Selenium爬取百度圣卡/网易白金卡手机靓号
  14. win10无法访问xp计算机,XP系统访问Win10打印机被拒绝的解决方法
  15. ambari mysql 密码_ambari密码重置
  16. 微信小程序开发之页面布局
  17. 计算机辅助教学在语文应用,多媒体计算机辅助教学在中学语文教学中应用.pdf...
  18. 未来教育计算机一级上网题每次都是零分,计算机一级MS模拟上网题为什么总是0分??!!...
  19. 转:拥抱挣扎:创造组织的同时,也创造了崭新的自我
  20. OSError: /home/yukang/anaconda3/envs/fsgan/lib/python3.9/site-packages/torch/lib/../../nvidia/cublas

热门文章

  1. 12行代码AC——试题 算法训练 猴子吃包子——解题报告
  2. python数组展示_python如何显示数组
  3. linux环境下ntp客户端,多种操作系统NTP客户端配置
  4. c语言素数个数_C语言试题及答案
  5. bigemap中下载边界_高清卫星地图:是可以看到人的地图,附下载方法
  6. gps导航原理与应用_一文读懂角速度传感器(陀螺仪)的应用场景
  7. pdf转图片 java_有将pdf文件转图片的格式方法吗?
  8. python findall函数_Ramp;Python Data Science系列:数据处理(11)Python正则表达式re模块(三)...
  9. hutool 读取扩展名文件_JPG,PNG,GIF,TIFF、SVG玩设计必须了解的文件格式你知道几个?...
  10. 群晖如何建php网站_群晖webstation搭建typecho博客