1. By now you have probably grown accustomed to the concise way data can be
decomposed and analyzed using pattern matching. This chapter shows you
how to generalize this concept further. Until now, constructor patterns were
linked to case classes. For instance, Some(x) is a valid pattern because Some
is a case class. Sometimes you might wish that you could write patterns like
this without creating an associated case class. In fact, you might wish to be
able to create your own kinds of patterns. Extractors give you a way to do
so. This chapter explains what extractors are and how you can use them to
define patterns that are decoupled from an object’s representation
到目前为止构造器模式只适用于case class,比如Some(x)是合法的,因为Some是个case class
有时候你想写于case class无关的模式,创建自己的模式。
2. An extractor in Scala is an object that has a method called unapply as one of its members
Scala 中的extractor就是带有unapply方法的对象
The purpose of that unapply method is to match a value and take it apart
这个方法的目的就是接收一个值,然后把它拆开
Often, the extractor object also defines a dual method apply for building values, but this is not required
通常一个extractor也会有apply方法,用来建立值,但这不是必须的
3. 如果一个object定义了unapply方法,这个对象的构造函数形式就可以出现在case语句后面,并把分解的结果与形式变量绑定
package chapter26 object Email extends App{ def unapply(str: String): Option[(String, String)] = { val parts = str split "@" if (parts.length == 2) Some(parts(0), parts(1) ) else None } val str = "#######@cn.ibm.com" str match { case Email(name, domain) => println("name:"+name + " domain:" + domain) case _ => println("match fail") } }
4. To bind N variables, an unapply would return an N-element tuple, wrapped in a Some.
要绑定N个变量, unapply就要返回用Some包装的N元组
5. unapplySeq
如果拆分的结果数量不确定,可以定义unapplySeq方法
package chapter26 object Domain extends App{ def unapplySeq(whole: String): Option[Seq[String]] = Some(whole.split("\\.").reverse) val dom = "cn.scala.org" dom match { case Domain("com", "sun", "java") => println("java.sun.com") case Domain("org", "scala", "cn") => println("cn.scala.org") case Domain(_*) => println("other domain") } }
6.Extractor还可以用于变量的分解
package chapter26 object Domain extends App{ def unapplySeq(whole: String): Option[Seq[String]] = Some(whole.split("\\.").reverse) val dom = "cn.scala.org" val Domain(x,y,z) = dom println(x) // org println(y) // scala println(z) // cn }
7.恍然大悟啊
you can access the elements of a list or an array
using sequence patterns such as:
List()
List(x, y, _*)
Array(x, 0, 0, _)
In fact, these sequence patterns are all implemented using extractors in the
standard Scala library. For instance, patterns of the form List(...) are
possible because the scala.List companion object is an extractor that defines an unapplySeq method.
之所以能对List做模式匹配是因为List对象定义了unapplySeq方法
8. 表示的独立性
Even though they are very useful, case classes have one shortcoming: they expose the concrete representation of data. This means that the name of the class in a constructor pattern corresponds to the concrete representation type of the selector object
虽然case class很有用,但是有一个缺点:它们曝露了数据的具体类型。 也就是说:构造器的名字对应一个具体的类型
If a match against:
case C(...)
succeeds, you know that the selector expression is an instance of class C.
如果 case C(...) 匹配成功,你就知道要匹配的那个对象是类C的实例
Extractors break this link between data representations and patterns. You
have seen in the examples in this section that they enable patterns that have
nothing to do with the data type of the object that’s selected on. This property
is called representation independence. In open systems of large size, representation independence is very important because it allows you to change an
implementation type used in a set of components without affecting clients of
these components.
Extractor打断了数据表示和数据类型的联系。 使得模式与数据类型无关。这个性质叫做表示的独立性。在一个大规模的开发系统中,表示的独立性是非常重要的。它允许你改变一个组件的实现,但不影响客户代码
9.正则表达式
One particularly useful application area of extractors are regular expressions.
Like Java, Scala provides regular expressions through a library, but extractors
make it much nicer to interact with them
Extractor使Scala与正则表达式的交互变得更加漂亮
package chapter26 object TestReg extends App { val decimal = """(-)?(\d+)(\.\d*)?""".r val input = "for -1.0 to 99 by 3" for (s <- decimal.findAllIn(input)) { println(s) } }