译者注:原文出处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; 使用方法...
IntellJIDEA Scala插件:scala-intellij-bin-2016.3.9
包含翻译后的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文档,用...
标签:11、parser、scala、combinators_2、lang、modules、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...
scala-SDK-4.7.0-vfinal-2.12-win32.win32.x86_64 scala-SDK-4.7.0-vfinal-2.12-win32.win32.x86_64
包含翻译后的API文档:scala-compiler-2.11.8-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.8; 标签:scala、lang、compiler、中英对照文档、jar包、java; 使用...
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文档、中英对照版; ...
包含翻译后的API文档:scala-compiler-2.11.12-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.12; 标签:scala、lang、compiler、中文文档、jar包、java; 使用方法:解压...
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 下载地址:...
IntelliJ IDEA 官网下载 scala 插件,为大家提速 scala-intellij-bin-2016.3.1.zip
scala-intellij-bin-2021.3.6.zip
scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!scala-intellij-bin-2018.3.2.zip插件,亲测可用!!!
scala-intellij-bin-2020.3.14.zip
包含翻译后的API文档:scala-compiler-2.12.7-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.12.7; 标签:scala、lang、compiler、中文文档、jar包、java; 使用方法:解压翻译...
包含翻译后的API文档:scala-compiler-2.11.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.scala-lang:scala-compiler:2.11.0; 标签:scala、lang、compiler、jar包、java、中文文档; 使用方法:解压翻译...
scala-intellij-bin-2019.1.9IDEA-scala插件,支持2019.1.X版IDEA。极难下载
包含翻译后的API文档:scala-xml_2.11-1.0.4-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.scala-lang.modules:scala-xml_2.11:1.0.4; 标签:scala、lang、modules、xml、中英对照文档、jar包、...
scala-intellij-bin-2020.2.3.zip
scala-SDK-4.2.0-vfinal-2.11-win32.win32.x86安装包。