译者注:原文出处http://danielwestheide.com/blog/2012/11/28/the-neophytes-guide-to-scala-part-2-extracting-sequences.html,翻译:Thomas
在第一篇中,我们知道了如何实现自己的提取器,如何在模式匹配中使用提取器。然而,我们仅仅讨论了从数据中提取固定数量参数的提取器,然而Scala可以针对一些序列数据类型提取任意数量的参数。
例如,你可以定义模式来匹配一个只包含两个元素或三个元素的list:
val xs = 3 :: 6 :: 12 :: Nil xs match { case List(a, b) => a * b case List(a, b, c) => a + b + c case _ => 0 }另外,如果你不在乎要匹配的list的具体长度,还可以使用通配操作符:_*:
val xs = 3 :: 6 :: 12 :: 24 :: Nil xs match { case List(a, b, _*) => a * b case _ => 0 }
上面这段代码中,第一个case被匹配到,xs的前两个元素分别被赋予a和b变量,同时不管列表中还剩余多少成员都忽略掉。
显然,这种用途的提取器不能用我在首篇中介绍的方法来实现。我们需要一种方式可以来定义一个提取器,它需要指定类型的参数输入并解构参数的数据到一个序列中,而这个序列的长度在编译时是未知的。
现在轮到unapplySeq出场了,这个方法就是用来实现上述场景的。我们来看下这方法的一种形式:
def unapplySeq(object: S): Option[Seq[T]]
它传入类型为S的参数,如果S完全不匹配则返回None,否则返回包含在Option中的类型为T的Seq。
例子:提取名字
我们来实现一个看上去不太实用的例子(译者注:这个例子只是为了说明如何实现unapplySeq,可以有更简单的方法实际想要的功能)。假设在我们的程序中,我接受字串形式保存的人名。
如果一个人有多个名字,字串里可能包含他的第二或第三名字。因此,可能存在的值会是"Daniel"、
"Catherina Johanna"或者
"Matthew John Michael"。我们想要匹配这些名字,并且提取出每个名字并赋给变量。
下面是用unapplySeq来实现的一个简单的提取器:
object GivenNames { def unapplySeq(name: String): Option[Seq[String]] = { val names = name.trim.split(" ") if (names.forall(_.isEmpty)) None else Some(names) } }
给定一个包含一个或多个名字的字串,会将这些名字分解提取成一个序列。如果给定的姓名连一个名字都不包含,提取器将返回None,因而,使用该提取器的模式将不被匹配。
现在来测试下这个提取器:
def greetWithFirstName(name: String) = name match { case GivenNames(firstName, _*) => "Good morning, " + firstName + "!" case _ => "Welcome! Please make sure to fill in your name!" }
这个简短的方法返回问候语,只提取第一个名字而忽略其它名字。greetWithFirstName("Daniel")
返回 "Good morning, Daniel!"
, 而 greetWithFirstName("Catherina Johanna")
返回 "Good morning, Catherina!"。
固定和可变数量参数提取的组合
有时候你可能想要提取在编译时就能够明确数量的值再加上可选的额外的一些值。
假设在前面的例子中,提供的名字包含人的完整姓名,而不仅仅是名字。可能的值如"John Doe"
和 "Catherina Johanna Peterson"。我们想要将这样的字串匹配成总是提取人的姓和第一个名到相应的变量,加上后面任意数量的名字。
我们可以将unapplySeq稍作修改,新的形式如下:
def unapplySeq(object: S): Option[(T1, .., Tn-1, Seq[T])]显然,unapplySeq也可以返回封装在Option中的TupleN,tuple里的最后元素必须得是有序类型。这个方法形式看上去有点熟悉,和我们前篇介绍的unapply方法相似。
下面是这种形式的实现:
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))) } }仔细来看一下返回类型和Some的拼装。这方法返回一个封装再Option中的Tuple3。这个tuple用Scala的语法糖来创建的-把三个元素(姓,第一个名和额外的名)包含在括号中。
当用于模式匹配时,此模式仅仅会匹配至少提供了姓和名的字串,额外名的序列值为丢弃掉姓名中第一个和最后一个词的序列。
我们用这个提取器来实现另一个问候方法:
def greet(fullName: String) = fullName match { case Names(lastName, firstName, _*) => "Good morning, " + firstName + " " + lastName + "!" case _ => "Welcome! Please make sure to fill in your name!" }
你可以随意的在REPL或worksheet里来试着运行下这些代码。
总结
我们在本篇中学到了如何实现一个提取可变数量参数的提取器。提取器是一个无比强大的机制,它们通常可以被灵活的复用,来扩展用于你要用来匹配的模型。
我们会在本系列文章最后的案例学习中再次讲解提取器。在下一篇中我会给一个在Scala中模式的多种不同用法的介绍-模型可不仅仅用于模型匹配哦。
更新, 24.01.2013: 感谢Christophe Bliard帮助发现的代码错误,我更新了GivenName提取器的代码。
作者:Posted by Daniel Westheide,2012.11.28
相关推荐
包含翻译后的API文档:scala-xml_2.12-1.0.6-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang.modules:scala-xml_2.12:1.0.6; 标签:scala、lang、modules、xml、中文文档、jar包、java; 使用方法...
包含翻译后的API文档:flink-scala_2.12-1.14.3-javadoc-API文档-中文(简体)版.zip 对应Maven信息:groupId:org.apache.flink,artifactId:flink-scala_2.12,version:1.14.3 使用方法:解压翻译后的API文档,用...
包含翻译后的API文档:scala-compiler-2.12.7-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.12.7; 标签:scala、lang、compiler、中文文档、jar包、java; 使用方法:解压翻译...
- **类型系统**:Scala具有强类型,支持类型推断,使得代码更简洁。 - **模式匹配**:允许开发者以一种声明式的方式处理数据结构。 - **高阶函数**:函数可以作为参数传递,也可以作为返回值。 - **类与对象**:...
4. **测试框架支持**:Scala插件通常会集成Scala的测试框架,如ScalaTest或Specs2,使得在IDE内创建和运行测试变得方便。 5. **额外的工具和库**:可能还包括Scala相关的工具和库,例如 sbt(Scala构建工具)的集成...
这个插件的版本号"2017.2.6"表明它是2017年第二季度的一个更新,版本6可能包含了该季度内的一些修复和改进。在那个时期,Scala正处于快速发展阶段,因此插件的更新通常会跟上语言的最新特性,确保开发者的体验。 ...
包含翻译后的API文档:scala-compiler-2.11.8-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.8; 标签:scala、lang、compiler、中英对照文档、jar包、java; 使用...
例如,它可以为Scala项目自动生成构建文件(如.sbt或.build.properties),帮助开发者编写类型安全的代码,并提供跳转到定义、查找引用和重构等功能。此外,它还支持ScalaTest和ScalaCheck等测试框架,便于进行单元...
标签:11、parser、scala、combinators_2、lang、modules、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...
scala-SDK-4.7.0-vfinal-2.12-linux.gtk.x86_64.tar.gz scala-SDK-4.7.0-vfinal-2.12-linux.gtk.x86_64.tar.gz
包含翻译后的API文档:scala-reflect-2.11.8-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.scala-lang:scala-reflect:2.11.8; 标签:reflect、scala、lang、jar包、java、API文档、中英对照版; ...
scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!
Scala是一种强大的多范式编程语言,它融合了函数式编程和面向对象编程的特点。IntelliJ IDEA是一款广受赞誉的Java开发集成环境,为开发者提供了高效、智能的代码编写体验。"scala-intellij-bin-0.41"是专门为...
`scala-intellij-bin-2018.3.5.zip` 和 `scala-intellij-bin-2018.3.6.zip` 是两个版本的Scala插件,分别适用于IntelliJ IDEA的2018.3.5和2018.3.6版本。这些插件是为了增强IDE对Scala语言的支持,提供代码高亮、...
"Scala-intellij-bin-2017.2.13"是针对IntelliJ IDEA的一个特定版本——2017.2.13的Scala插件,这个插件使得在IntelliJ中编写、调试和运行Scala代码变得轻而易举。 Scala插件的安装和配置是开发Scala项目的关键步骤...
包含翻译后的API文档:scala-compiler-2.11.12-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.12; 标签:scala、lang、compiler、中文文档、jar包、java; 使用方法:解压...
"scala-intellij-bin-2019.1.2.zip"这个压缩包就是针对IntelliJ IDEA的Scala插件,版本为2019.1.2,用于增强IDE对Scala语言的支持。 首先,我们需要理解Scala插件的作用。在IntelliJ IDEA中安装此插件后,用户可以...
2. **模式匹配**:Scala的模式匹配功能使得处理数据结构和解析数据变得更加简单,它可以与case类和枚举类型一起使用,实现强大的数据解构。 3. **函数式编程**:Scala支持高阶函数和闭包,可以定义匿名函数,使用...
scala eclipse插件.对应scala版本:2.10--2.11,对应eclipes版本:4.4--4.5. update site:http://download.scala-ide.org/sdk/lithium/e44/scala211/stable/site 下载地址:...
标签:11、xml_2、scala、lang、modules、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...