《Programming in Scala 3rd》阅读笔记

Chapter 26《Extractors》

2018-08-14  本文已影响0人  liqing151

提取器

object EMail {
// The injection method (optional)
def apply(user: String, domain: String) = user + "@" + domain
// The extraction method (mandatory)
def unapply(str: String): Option[(String, String)] = {
val parts = str split "@"
if (parts.length == 2) Some(parts(0), parts(1)) else None
}
}

定义了一个名为EMail的提取器。unapply方法是apply方法的逆操作,unapply的入参为email地址,返回userdomain,但是为了处理字符串不是email的情况,将unapply的返回值定义为Option类型。在模式匹配中,如果case后面遇到了提取器,就调用unapply方法,其入参是选择表达式。

selectorString match { case EMail(user, domain) => ... }
EMail.unapply(selectorString)

unapply方法的返回值必须是Option类型的。这里的case Email(param1)模式,如果没有定义apply方法,有两种写法,第一种是Email(param1),这个param1unapply返回的整个元组;第二种就是Email(param1, param2, ……),参数的个数和unapply定义的返回参数个数相同。定义了apply方法也是同样的情况。

目前选择器selectorString的类型和提取器unapply的参数类型是一致的,都是String,但这并不是必须的,selectorString可以为任何类型,unapply会首先检查selectorString的类型是不是String类型的,applyunapply是对偶的,如果两者存在于一个对象中的话,Email.unapply(Email.apply(user, domain))的返回值是Some(user, domain)apply使用参数来构建对象,unapply将对象解析为构造参数。推荐将两者放在一起。


0个或者1个变量的模式

object UpperCase {
def unapply(s: String): Boolean = s.toUpperCase == s
}

case EMail(Twice(x @ UpperCase()), domain)中含有三个unapply模式。UpperCase()要带上,不然匹配的就是UpperCase自身的类型。UpperCase自身虽然没有绑定任何变量,但可以使用变量绑定@将跟它匹配的模式关联一个变量,DIDI@xiaomi.com返回的x就是DI,可见嵌套的模式匹配是从最外层进行的。


提取可变长度参数的模式

如何使用提取器支持下面的代码:

dom match {
case Domain("org", "acm") => println("acm.org")
case Domain("com", "sun", "java") => println("java.sun.com")
case Domain("net", _*) => println("a .net domain")
}

就是一个提取器可生成多个匹配模式,使用unapplySeq方法。

def unapplySeq(whole: String): Option[Seq[String]] Some(whole.split("\\.").reverse)

返回的是Option[Seq[String]]类型。

def unapplySeq(email: String): Option[(String, Seq[String])] 

既能够返回固定元素String,也能够返回不定元素,不定元素需要写在最后面。这里的Seq也可以换成List,Array,IndexedSeq等。


提取器和序列模式


提取器和样例类的比较


正则表达式

scala> val Decimal = new Regex("""(-)?(\d+)(\.\d*)?""")

或者 val Decimal = """(-)?(\d+)(\.\d*)?""".r,因为在StringOps中存在一个名为r的方法可以生成Regex表达式。

查找正则表达式
使用正则表达式提取信息
scala> val Decimal(sign, integerpart, decimalpart) = "-1.23"
sign: String = -
integerpart: String = 1
decimalpart: String = .23

可绑定的变量是正则表达式中的各个组。

上一篇 下一篇

猜你喜欢

热点阅读