Programming in Scala (Second Edition) 读书笔记26 Extractors

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)
  }
}


你可能感兴趣的:(scala)