scala模式匹配 if
前言
这是面向初学者的Scala教程的第3部分。 该博客上还有其他文章,您可以在我正在为其创建的计算语言学课程的链接页面上找到这些链接和其他资源。 此外,您可以在“ JCG Java教程”页面上找到本教程和其他教程系列。
有条件的
变量来了,变量就去了,根据输入,它们取不同的值。 我们通常需要根据这些值制定不同的行为。 例如,让我们模拟奥斯丁的一家酒吧招标,该酒吧必须确保他不给21岁以下的人喝酒。
scala> def serveBeer (customerAge: Int) = if (customerAge >= 21) println("beer") else println("water")
serveBeer: (customerAge: Int)Unit
scala> serveBeer(23)
beer
scala> serveBeer(19)
water
我们在这里所做的是标准使用条件来产生一个动作或另一个动作-在这种情况下,仅打印一条消息或另一则消息。 if(…)中的表达式是一个布尔值,可以为true或false 。 您可以通过直接执行不等式来看到这一点:
scala> 19 >= 21
res7: Boolean = false
并且这些表达式可以根据布尔值的合取和合取的标准规则进行组合。 连词用&&表示,而||表示析取 。
scala> 19 >= 21 || 5 > 2
res8: Boolean = true
scala> 19 >= 21 && 5 > 2
res9: Boolean = false
要检查是否相等,请使用== 。
scala> 42 == 42
res10: Boolean = true
scala> "the" == "the"
res11: Boolean = true
scala> 3.14 == 6.28
res12: Boolean = false
scala> 2*3.14 == 6.28
res13: Boolean = true
scala> "there" == "the" + "re"
res14: Boolean = true
等于运算符==与赋值运算符=不同,如果尝试将=用于相等性测试,则会出现错误。
scala> 5 = 5
:1: error: ';' expected but '=' found.
5 = 5
^
scala> x = 5
:10: error: not found: value x
val synthvar$0 = x
^
:7: error: not found: value x
x = 5
^
第一个示例是完全不好的,因为我们不能希望将值分配给像5这样的常量。在第二个示例中,错误抱怨找不到值x 。 那是因为它是一个有效的构造,假设先前已经定义了var变量x 。
scala> var x = 0
x: Int = 0
scala> x = 5
x: Int = 5
回想一下,使用var变量,可以为它们分配一个新值。 但是,实际上并不需要经常使用var,并且坚持使用val有很多优点。 在我们进行过程中,我将帮助您从这些角度进行思考。 现在,请尝试忽略该语言中存在var的事实!
回到条件。 首先,这里有更多比较运算符:
x!= y(x不等于y)
x> y(x大于y) x
这些运算符可用于具有自然顺序的任何类型,包括字符串。
scala> "armadillo" < "bear"
res25: Boolean = true
scala> "armadillo" < "Bear"
res26: Boolean = false
scala> "Armadillo" < "Bear"
res27: Boolean = true
显然,这不是您惯常使用的字母顺序。 而是基于ASCII字符编码。
关于Scala中的条件,一个非常美丽而有用的事情是它们返回一个值。 因此,以下是设置变量x和y的值的有效方法。
scala> val x = if (true) 1 else 0
x: Int = 1
scala> val y = if (false) 1 else 0
y: Int = 0
这里不是那么令人印象深刻,但让我们回到调酒师,而不是使用serveBeer函数打印一个String,我们可以让它返回一个代表饮料的String,对于21岁以上的人为 “啤酒”,否则为“水” 。
scala> def serveBeer (customerAge: Int) = if (customerAge >= 21) "beer" else "water"
serveBeer: (customerAge: Int)java.lang.String
scala> serveBeer(42)
res21: java.lang.String = beer
scala> serveBeer(20)
res22: java.lang.String = water
请注意,第一个serveBeer函数如何返回Unit,但此函数返回String。 单位表示不返回任何值-通常由于我们不会在这里讨论的原因而建议不要这样做。 不管怎样,上面显示的条件赋值的一般模式是您会经常使用的东西。
条件语句还可以具有多个if和else 。 例如,假设酒保只是向每位顾客提供适合年龄的饮料,而21岁以上的人会喝啤酒,青少年喝苏打水,小孩应该喝果汁。
scala> def serveDrink (customerAge: Int) = {
| if (customerAge >= 21) "beer"
| else if (customerAge >= 13) "soda"
| else "juice"
| }
serveDrink: (customerAge: Int)java.lang.String
scala> serveDrink(42)
res35: java.lang.String = beer
scala> serveDrink(16)
res36: java.lang.String = soda
scala> serveDrink(6)
res37: java.lang.String = juice
当然,在任何IFS 否则IFS的布尔表达式可以是复杂的连词和小表情析取。 现在让我们考虑一个面向计算语言学的示例,它可以利用这一点,并且我们将在以后的教程中继续进行构建。
每个人(希望如此)都知道词性是什么。 (如果没有,请查看YouTube上的Grammar Rock。)在计算语言学中,我们倾向于使用非常详细的标记集,其远远超出了“名词”,“动词”,“形容词”等等。 例如, 来自Penn Treebank的标签集将NN用于单数名词(表格),将NNS用于复数名词(表格),将NNP用于单数专有名词(约翰),以及将NNPS用于复数专有名词(维京人)。
这是一个带注释注释的句子,带有Penag Treebank的《华尔街日报》部分第一句中的postags,格式为word / postag。
我们将看到如何处理这些集体不久,但现在,让我们建立一个回合单一标签,如“NNP”转变为“NN”和“JJS”到“JJ”,使用条件语句的功能。 我们将其他所有Postag保持原样。
我们将从一个次优的解决方案开始,然后对其进行完善。 您可能要尝试的第一件事是为每个完整表单标签创建一个案例,并输出其相应的缩短标签。
scala> def shortenPos (tag: String) = {
| if (tag == "NN") "NN"
| else if (tag == "NNS") "NN"
| else if (tag == "NNP") "NN"
| else if (tag == "NNPS") "NN"
| else if (tag == "JJ") "JJ"
| else if (tag == "JJR") "JJ"
| else if (tag == "JJS") "JJ"
| else tag
| }
shortenPos: (tag: String)java.lang.String
scala> shortenPos("NNP")
res47: java.lang.String = NN
scala> shortenPos("JJS")
res48: java.lang.String = JJ
因此,它可以完成工作,但是有很多冗余-特别是在很多情况下,返回值都是相同的。 我们可以使用析取来处理这个问题。
def shortenPos2 (tag: String) = {
if (tag == "NN" || tag == "NNS" || tag == "NNP" || tag == "NNP") "NN"
else if (tag == "JJ" || tag == "JJR" || tag == "JJS") "JJ"
else tag
}
这些在逻辑上是等效的。
使用字符串的属性,有一种更简单的方法。 在这里, startsWith方法非常有用。
scala> "NNP".startsWith("NN")
res51: Boolean = true
scala> "NNP".startsWith("VB")
res52: Boolean = false
我们可以使用它来简化postag缩短功能。
def shortenPos3 (tag: String) = {
if (tag.startsWith("NN")) "NN"
else if (tag.startsWith("JJ")) "JJ"
else tag
}
这使得添加附加条件变得非常容易,该附加条件会使所有的动词标签折叠到“ VB”。 (左为练习。)
关于条件赋值的最后一点:它们可以返回您喜欢的任何东西,因此,例如,以下内容都是有效的。 例如,这是一个(非常)简单(且非常不完善)的英语词干分析器,返回词干和后缀。
scala> def splitWord (word: String) = {
| if (word.endsWith("ing")) (word.slice(0,word.length-3), "ing")
| else if (word.endsWith("ed")) (word.slice(0,word.length-2), "ed")
| else if (word.endsWith("er")) (word.slice(0,word.length-2), "er")
| else if (word.endsWith("s")) (word.slice(0,word.length-1), "s")
| else (word,"")
| }
splitWord: (word: String)(String, java.lang.String)
scala> splitWord("walked")
res10: (String, java.lang.String) = (walk,ed)
scala> splitWord("walking")
res11: (String, java.lang.String) = (walk,ing)
scala> splitWord("booking")
res12: (String, java.lang.String) = (book,ing)
scala> splitWord("baking")
res13: (String, java.lang.String) = (bak,ing)
如果我们想直接使用带有变量的词干和后缀,则可以立即为其分配它们。
scala> val (stem, suffix) = splitWord("walked")
stem: String = walk
suffix: java.lang.String = ed
匹配
Scala提供了另一种非常强大的方法来对条件执行进行编码,称为matching 。 它们与if-else块有很多共同点,但是具有一些不错的附加功能。 我们将返回postag缩短器,从标签的完整列表以及每种情况下的操作开始,例如我们第一次尝试使用if-else。
def shortenPosMatch (tag: String) = tag match {
case "NN" => "NN"
case "NNS" => "NN"
case "NNP" => "NN"
case "NNPS" => "NN"
case "JJ" => "JJ"
case "JJR" => "JJ"
case "JJS" => "JJ"
case _ => tag
}
scala> shortenPosMatch("JJR")
res14: java.lang.String = JJ
注意,最后一种情况下带有下划线“ _”是默认的操作,类似于if-else块末尾的“ else”。
将此函数与之前的if-else函数shortPos进行比较,该函数在其形式定义中具有很多重复“ else if(tag == “。match语句允许您执行相同的操作,但是更加简洁明了,很多当然,我们可以缩短时间。
def shortenPosMatch2 (tag: String) = tag match {
case "NN" | "NNS" | "NNP" | "NNPS" => "NN"
case "JJ" | "JJR" | "JJS" => "JJ"
case _ => tag
}
这比之前定义的if-else shortPosMatch2更具可读性。
除了可读性之外,match语句还提供了一些逻辑保护。 例如,如果您不小心有两个重叠的案例,那么您将得到一个错误。
scala> def shortenPosMatchOops (tag: String) = tag match {
| case "NN" | "NNS" | "NNP" | "NNPS" => "NN"
| case "JJ" | "JJR" | "JJS" => "JJ"
| case "NN" => "oops"
| case _ => tag
| }
:10: error: unreachable code
case "NN" => "oops"
这是一个显而易见的示例,但是具有更复杂的匹配选项,可以使您免于错误!
我们不能像使用if-else shortPosMatch3一样使用startsWith方法。 但是,我们可以在match语句中很好地使用正则表达式,我们将在后面的教程中介绍。
match语句真正发挥作用的地方在于,它们不仅可以对简单变量(如Strings和Ints)的值进行匹配,还可以进行匹配。 匹配的一种用法是检查函数的输入类型,该函数可以采用许多类型的超类型。 回想一下Any是所有类型的超类型; 如果我们有以下函数采用任何类型的参数,则可以使用匹配检查参数的类型,并相应地执行不同的行为。
scala> def multitypeMatch (x: Any) = x match {
| case i: Int => "an Int: " + i*i
| case d: Double => "a Double: " + d/2
| case b: Boolean => "a Boolean: " + !b
| case s: String => "a String: " + s.length
| case (p1: String, p2: Int) => "a Tuple[String, Int]: " + p2*p2 + p1.length
| case (p1: Any, p2: Any) => "a Tuple[Any, Any]: (" + p1 + "," + p2 + ")"
| case _ => "some other type " + x
| }
multitypeMatch: (x: Any)java.lang.String
scala> multitypeMatch(true)
res4: java.lang.String = a Boolean: false
scala> multitypeMatch(3)
res5: java.lang.String = an Int: 9
scala> multitypeMatch((1,3))
res6: java.lang.String = a Tuple[Any, Any]: (1,3)
scala> multitypeMatch(("hi",3))
res7: java.lang.String = a Tuple[String, Int]: 92
因此,例如,如果它是一个Int,我们可以做乘法之类的事情,如果它是一个布尔型,我们可以对它进行取反(用!),依此类推。 在case语句中,我们提供了一个具有匹配类型的新变量,然后在箭头=>之后,我们可以以类型安全的方式使用该变量。 稍后,我们将看到如何创建类(特别是案例类),其中定期使用这种基于匹配的函数。
同时,这是一个简单加法函数的示例,该函数允许输入一个String或Int来指定其参数。 例如,我们想要的行为是这样的:
scala> add(1,3)
res4: Int = 4
scala> add("one",3)
res5: Int = 4
scala> add(1,"three")
res6: Int = 4
scala> add("one","three")
res7: Int = 4
假设我们只处理拼写为1到5的版本,并且我们不能处理的任何字符串(例如“ six”和aardvark”)都被视为0。然后以下两个使用match的函数对其进行处理。
def convertToInt (x: String) = x match {
case "one" => 1
case "two" => 2
case "three" => 3
case "four" => 4
case "five" => 5
case _ => 0
}
def add (x: Any, y: Any) = (x,y) match {
case (x: Int, y: Int) => x + y
case (x: String, y: Int) => convertToInt(x) + y
case (x: Int, y: String) => x + convertToInt(y)
case (x: String, y: String) => convertToInt(x) + convertToInt(y)
case _ => 0
}
就像if-else块一样,匹配项可以返回您喜欢的任何类型,包括元组,列表等。
匹配块用于许多其他有用的上下文中,我们将在后面介绍。 同时,还需要指出,匹配实际上是在变量分配中使用的。 我们已经在Tuples中看到了它,但是可以通过Lists和其他类型来完成。
scala> val (x,y) = (1,2)
x: Int = 1
y: Int = 2
scala> val colors = List("blue","red","yellow")
colors: List[java.lang.String] = List(blue, red, yellow)
scala> val List(color1, color2, color3) = colors
color1: java.lang.String = blue
color2: java.lang.String = red
color3: java.lang.String = yellow
当使用Scala创建脚本时,在命令行中使用args Array的情况下,这尤其有用。 例如,考虑一个运行如下的程序。
$ scala nextYear.scala John 35
Next year John will be 36 years old.
这是我们的方法。 (将接下来的两行另存为nextYear.scala并尝试一下。)
val Array(name, age) = args
println("Next year " + name + " will be " + (age.toInt + 1) + " years old.")
注意,我们必须做age.toInt 。 这是因为age本身是String,而不是Int。
使用if-else块和match块进行条件执行是将复杂行为构建到您经常看到和使用的程序中的重要组成部分!
参考: 对于初学者来说,Scala的第一步,来自Bcompose博客的JCG合作伙伴 Jason Baldridge的 第3部分 。
相关文章 :
- Scala教程– Scala REPL,表达式,变量,基本类型,简单函数,保存和运行程序,注释
- Scala教程–元组,列表,列表和字符串上的方法
- Scala教程–迭代,用于表达式,产量,图,过滤器,计数
- Scala教程–正则表达式,匹配
- Scala教程–使用scala.util.matching API进行正则表达式,匹配和替换
- Scala教程–地图,集合,groupBy,选项,展平,flatMap
- Scala教程– scala.io.Source,访问文件,flatMap,可变地图
- Scala教程–对象,类,继承,特征,具有多个相关类型的列表,适用
- Scala教程–脚本编写,编译,主要方法,函数的返回值
- Scala教程– SBT,scalabha,软件包,构建系统
- Scala教程–代码块,编码样式,闭包,scala文档项目
- Scala中功能组合的乐趣
- Scala如何改变我对Java代码的思考方式
- Scala中删除了Java的哪些功能?
- 用Scala测试
- 每个程序员都应该知道的事情
翻译自: https://www.javacodegeeks.com/2011/09/scala-tutorial-conditional-execution.html
scala模式匹配 if