译者注:原文出处http://danielwestheide.com/blog/2012/12/05/the-neophytes-guide-to-scala-part-3-patterns-everywhere.html,翻译:Thomas
在前两篇中,我花了不少时间解释了case class在模式中如何解构的,如何实现能够以任何方式提取任何类型数据的提取器。
到目前为止你只看到少数使用模式的方法,现在是时候来看看在你的Scala代码里该如何用上模式,我们开始吧!
模式匹配表达式
模式时常会出现的场景是在模式匹配表达式里,在参加了Coursera的Scala课程或者完整看了前两篇文章后,你应该对这种用法很熟悉了。首先有个表达式e,后面跟着match关键字和一个代码块,代码块里可以包含任意多个case子句。一个case子句由case关键字开头 后面跟着模式和一个可选的防护从句,后面跟随着模式匹配成功后要执行的一段代码。
下面是一个使用了模式和一个包含了防护从句的case的简单的例子:
case class Player(name: String, score: Int) def printMessage(player: Player) = player match { case Player(_, score) if score > 100000 => println("Get a job, dude!") case Player(name, _) => println("Hey " + name + ", nice to see you again!") }
printMessage方法的返回类型是
Unit
, 它的唯一目的是执行副作用,即打印一个信息。有一点很重要,你不一定非得在这里用模式匹配,可以当成类似Java里的switch语句一样。在这里称作模式匹配表达式是有原因的,整个match的返回值是第一个被匹配的模式的返回值。
通常,用上它的这个特性是一个好办法,这让你可以解耦两个原本不属于一样的事情,也让你的代码更容易测试。我们可以将上面的代码重写一下:
def message(player: Player) = player match { case Player(_, score) if score > 100000 => "Get a job, dude!" case Player(name, _) => "Hey " + name + ", nice to see you again!" } def printMessage(player: Player) = println(message(player))现在我们有了一个返回String类型的message方法。现在它是一个纯函数了,返回的是模式匹配的结果。你当然可以把结果赋给一个常量。
在常量/变量定义时使用模式
在Scala中还可以把模式用在常量定义语句的左侧(变量定义里当然也可以用,不过我们还是想尽量保持Scala代码的函数式风格,所以你在我的系列文章里不会看到太多的变量的使用)。假设我们有一个方法会返回当前玩家,我们先实现一个假的方式总是返回一个固定的玩家:
def currentPlayer(): Player = Player("Daniel", 3500)通常你的常量定义看起来是这样的:
val player = currentPlayer() doSomethingWithTheName(player.name)如果你是个Python程序员,也许对序列解包功能很熟悉。Scala提供类似的功能,你可以在常量定义语句的左侧使用任何模式,我们来将上面的代码改造一下,让它可以结构player后再赋值给指定常量:
val Player(name, _) = currentPlayer() doSomethingWithTheName(name)你可以拿任意模式用作此用途,不过通常你得要确保模式总是被匹配的,否则你就会面临运行时异常。例如,下面的例子就会有问题。scores是一个返回得分列表的方法,在下面的代码中,这方法如果返回的是空列表就会导致问题:
def scores: List[Int] = List() val best :: rest = scores println("The score of our champion is " + best)看,程序丢出来一个MatchError。结果就是我们的游戏程序跑不下去了,因为没有获取到游戏成绩。
想要这样来使用模式,最好的方法是结构case class,你可以在编译时就能确定它们的类型。如果同时还使用了tuple的话,可以让你的代码可读性更好。假设我们有一个函数返回一个tuple包装的玩家的名字和他的得分,不再使用Player类了:
def gameResult(): (String, Int) = ("Daniel", 3500)
访问tuple的元素看上去会让人感觉迷惑:
val result = gameResult() println(result._1 + ": " + result._2)这时在常量定义时用模式来结构会是安全的,因为我们清楚我们面对的是一个Tuple2数据类型:
val (name, score) = gameResult() println(name + ": " + score)这比前一段代码更可读,不是吗?
在for语句中使用模式
在for语句中使用模式也很有价值。举例来说,for语句里可以包含常量的定义。前面介绍的在常量定义语句的左侧使用模式的用法在for语句里也适用。如果我们想在我们的游戏程序里实现名人堂-即得分超过一个阈值的玩家名单。我们可以用for语句实现一段可读性强的代码:
def gameResults(): Seq[(String, Int)] = ("Daniel", 3500) :: ("Melissa", 13000) :: ("John", 7000) :: Nil def hallOfFame = for { result <- gameResults() (name, score) = result if (score > 5000) } yield name
hallOfFame的结果会是List("Melissa", "John")
, 因为第一个玩家没有满足守卫子句的条件。
我们还可以进一步精简一下代码,在for语句里,generator的左侧也可以是模式。所以我们可以不用引进result常量,可以直接在generator左侧用模式来解构:
def hallOfFame = for { (name, score) <- gameResults() if (score > 5000) } yield name在这里例子里,模式(name,score)总是匹配的,所以在没有守卫子句if (score > 5000)时,这段代码就相当于把tuple转成玩家名字 。
相关推荐
包含翻译后的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文档:scala-compiler-2.12.7-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.12.7; 标签:scala、lang、compiler、中文文档、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文档,用...
"scala-intellij-bin-2016.3.9"是针对Scala语言的一个特定版本的IntelliJ IDEA插件,该版本为2016.3.9。这个插件是专门为Scala开发者设计的,旨在提高他们在IntelliJ IDEA中的开发体验。 Scala是一种多范式编程语言...
- **社区支持**:IntelliJ IDEA拥有庞大的开发者社区,提供丰富的第三方插件和资源。 总之,"scala-intellij-bin-2020.2.3.zip" 提供了在IntelliJ IDEA中进行高效Scala开发所需的工具集。通过使用这个插件,开发者...
在函数式编程方面,Scala提供了高阶函数、柯里化、模式匹配、不可变数据结构等特性,这些在IntelliJ IDEA的Scala插件中都有良好的支持。通过IDE,开发者可以方便地使用这些功能,提升代码的简洁性和可读性。 对于...
包含翻译后的API文档:scala-compiler-2.11.8-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.8; 标签:scala、lang、compiler、中英对照文档、jar包、java; 使用...
标签: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
scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!
包含翻译后的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.5.zip` 和 `scala-intellij-bin-2018.3.6.zip` 是两个版本的Scala插件,分别适用于IntelliJ IDEA的2018.3.5和2018.3.6版本。这些插件是为了增强IDE对Scala语言的支持,提供代码高亮、...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性。IntelliJ IDEA是一款广受赞誉的Java集成开发环境(IDE),它为开发者提供了丰富的工具和功能来提升开发效率。"Scala-intellij-bin-2017.2.13...
Scala是一种强大的多范式编程语言,它融合了函数式编程和面向对象编程的特点。IntelliJ IDEA是一款广受赞誉的Java开发集成环境,为开发者提供了高效、智能的代码编写体验。"scala-intellij-bin-0.41"是专门为...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的概念。IntelliJ IDEA是一款广受欢迎的集成开发环境(IDE),尤其在Java和...如果你是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 下载地址:...
此外,该插件还支持Scala的模式匹配、匿名函数、特质等特性,使得IDE能更好地理解和处理这种高度抽象的语言。 代码重构是软件开发中的重要环节,Scala插件提供了诸如提取方法、重命名变量、移动类等重构操作,确保...
包含翻译后的API文档:scala-compiler-2.11.12-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.12; 标签:scala、lang、compiler、中文文档、jar包、java; 使用方法:解压...
包含翻译后的API文档:scala-xml_2.11-1.0.1-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang.modules:scala-xml_2.11:1.0.1; 标签:11、xml_2、scala、lang、modules、jar包、java、中文文档; ...
2. **模式匹配**:Scala的模式匹配功能使得处理数据结构和解析数据变得更加简单,它可以与case类和枚举类型一起使用,实现强大的数据解构。 3. **函数式编程**:Scala支持高阶函数和闭包,可以定义匿名函数,使用...