欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习!
模式匹配和样例类
更好的switch
var sign = ...
val ch: Char = ...
ch match {
case '+' => sign = 1
case '-' => sign = -1
case _ => sign = 0
}
守卫
守卫可以是任何Boolean条件。
ch match {
case '+' => sign = 1
case '-' => sign = -1
case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10)
case _ => sign = 0
}
模式中的变量
如果case关键字后面跟着一个变量名,那么匹配的表达式会被赋值给那个变量。
str(i) match {
case '+' => sign = 1
case '_' => sign = -1
case ch digit = Character.digit(ch, 10)
}
类型模式
在Scala中,我们更倾向于使用这样的模式匹配:
obj match {
case x: Int => x
case s: Striong => Integer.parseInt(s)
case _: BigInt => Int.MaxValue
case _ => 0
}
匹配数组,列表,元组
要匹配数组的内容,你可以使用Array表达式:
arr match {
case Array[0] => "0"
case Array(x, y) => x + " " + y
case Array(0, _*) => "0..."
case _ => "Something else"
}
第一个模式匹配包含0的数组。
第二个模式匹配任何带有两个元素的数组,并将这两个元素分别绑定到变量x和y。
第三个表达式匹配任何以零开始的数组。
列表:
lst match {
case 0 :: Nil => "0"
case x :: Nil => x + " " + y
case 0 :: tail => "0..."
case _ => "Something else"
}
元组
pair match {
case (0, _) => "0..."
case (y, 0) => y + " 0"
case _ => "neither is 0"
}
变量声明中的模式
Scala代码可以这样写:
val (x, y) = (1, 2)
//同时将x定义为1, 把y定义为2。
//这对于使用那些返回对偶的函数很有用。
//同样,可以用于任何带有变量的模式:
val Array(first, second, _*) = arr
//以上代码是将数组的第一个和第二个元素分别赋值给first和second.
for表达式中的模式
import scala.collection.JavaConversions.propertiesAsScalaMap
//将Java的Properties转换成Scala映射--只是为了做出一个示例:
for ((k, v) <- System.getProperties())
println(k + "->" + v)
样例类
abstract class Amount
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
//
case object Nothing extends Amount
copy方法和带名参数
val amt = Currency(29.95, "EUR")
val price = amt.copy()
//改进
val price = amt.copy(value = 19.3) //Currency(19.3, "EUR")
//或者:
val price = amt.copy(unit = "CHF") //Currency(29.95, "CHF")
case语句中的中置表示法
amt match {
case a Currency u => ...
}
//等同于case Currency(a, u)
匹配嵌套结构
样例类经常被用于嵌套结构。
abstract class Item
case class Article(description: String, price: Double) extends Item
case class Bundle(description: String, discount: Double, items: Item*) extends Item
我们可以很容易给出嵌套对象定义
Bundle("Father's day sprcial", 20.0, Article("Scala for the impatient", 39.95))
Bundle("Anchor Distillery Sampler", 10.0,
Article("Old potrero Straight rye whisky", 79.95),
Article("Junipero Gin", 79.95))
模式可以匹配到特定的嵌套,
case Bundle(_, _, Article(descr, _), _*) => ...
同样,你也可以用@表示法将嵌套的值绑定到变量:
case Bundle(_, _, arg @ Article(_, _), rest @ _*) => ...
在本例中,_*是必需的。
密封类
sealed关键字
sealed abstract class Amount
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
模拟枚举
sealed abstract class TrafficLightColor
case object Red extends TrafficLightColor
case object Yellow extends TrafficLightColor
case object Green extends TrafficLightColor
color match {
case Red => "stop"
case Yellow => "hurry up"
case Green => "go"
}
注意超类被声明为sealed,让编译器可以帮助我们检查match语句是否完整。
Option类型
标准类库中的Option类型用样例来表示那种可能存在,也可能不存在的值。这比使用空字符串的意图更加清晰,比使用null来表示缺少某值的做法更加安全。
Option支持泛型。
Map类的get方法返回一个Option。如果对于给定的键没有对应的值,则get返回None.如果有值,就会将该值包在Some中返回。
scores.get("Alice") match {
case Some(score) => println(score)
case None => println("No score")
}
偏函数
被包在花括号内的一组case语句是一个偏函数–>一个并非对所有输入值都有定义的函数。
它是PartialFunction[A, B]类的一个实例。(A是参数类型,B是返回类型)
val f: PartialFunction[Char, Int] = {
case '+' => 1
case '-' => -1
}
f('-') //调用f.apply('-'),返回-1
f.isDefinedAt('0') //false
f('0') //抛出MatchError
偏函数表达式必须位于编译器可以推断出返回类型的上下文中。当你把它赋值给一个带有类型声明的变量,或者将它作为参数传递时,都符合这个要求。
欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习!