Scala中的Extractor

Scala中使用unapply方法可以实现三种extractor(另外使用unapplySeq也可以实现extractor)

  1. def unapply(object: S): Option[(T1, ..., Tn)]
  2. def unapply(object: S): Option[T]
  3. def unapply(object: S): Boolean

感觉第三种extractor的使用形式有些奇怪。比如,下面是《快学Scala》中的一个例子:

object Name {
  def unapply(input: String) = {
    val pos = input.indexOf(" ")
    if(pos == -1) None
    else Some(input.substring(0, pos), input.substring(pos + 1))
  }
}
object IsCompound {
  def unapply(input: String) = input.contains(" ")
}

  这里定义了两个extractor: Name和IsCompound, 前者返回Option[String], 后者返回Boolean

可以这么使用这两个extractor

author match {
  case Name(first, last @ IsCompound()) => ...
  case Name(first, last) => ...
}

问题是:

  1. 怎么理解返回值为Boolean的extractor呢?
  2. IsCompound()后边的()不能省略,也不能像返回option的extractor一样绑定变量,比如IsCompound(isComp), 该怎么理解这种行为呢?

在这篇文章

The Neophyte‘s Guide to Scala Part 1: Extractors

里找到了答案。



之所以觉得这种形式比较奇怪,还是对extractor的概念理解得有些模糊,没有搞清楚那种match的形式到底干了个啥。

拿最简单的形式为例

object Test extends App{
  val author = "Dan Simmons"
  author match{
    case Name(firstName, lastName) => println(s"""Hello, Mr $lastName""")
    case _ =>
  }
}

输出:Hello, Mr Simmons

首先这是一个pattern matching。当某个case分支匹配成功后,就会执行 =>后的语句。

那什么样算是匹配成功呢?

这就跟具体的extractor有关了,对于返回Option的提取器,如果调用unapply方法成功返回Some,就算是成功。对于返回Boolean的提取器,如果调用unapply方法返回true,那就是匹配成功。

在这个pattern matching里,第一个case使用的Name这个提取器匹配成功,它对author这个字符串进行了“解构”,其结果是定义了两个新的变量:firstName和lastName。

当使用返回Boolean的extractor时,我们并不是进行解构,而是进行判断。因此,返回Boolean的extractor在进行匹配后,不会定义新变量;但是为了与类型匹配分开,也不能直接用提取器的名字而不跟括号。 返回Boolean的提取器,在使用时,只能使用extractor的名字加上()这种形式。像下面这样

  author match{
    case IsCompound() => println("is compound")//IsCompound()里的()不能省
    case _ =>
  }

也可以把这两种extractor混合起来

  author match{
    case Name(first, last @ IsCompound()) => println("has a compound last name")
    case Name(first, last) => println("don‘t has a compound name")
    case _ =>
  }

第一个case是一种复合匹配,只有当Name这个extractor匹配成功,并且提取出来的第二个变量匹配成功IsCompound()时,整个模式才会匹配成功。在这里@定义了一个变量last,把它绑定到成功匹配了IsCompound的那个值上。

时间: 2024-11-13 11:53:31

Scala中的Extractor的相关文章

scala中trait学习笔记

scala中提供的trait(特质)和Java中的Interface有很多相似之处.都可以持有方法的声明和属性,但是trait还有比interface强大的多的其他用法. 1. trait可以带有方法实现: 2. trait与interface一样,可以互相继承.但是trait可以继承自某个类,但是这种特质只能够混入父类的子类中,不能随意混入: 3. trait中可以在运行时动态调用方法. 下面举一个trait使用的例子. 首先定义一个虚类IntQueue和特质Logger abstract c

转载: scala中span和partition区别

scala中的partition span splitAt groupBy 可把Collection分成:满足条件的一组,其他的另一组. partitionspan List(1,9,2,4,5).span(_<3)       // (List(1),List(9, 2, 4, 5)),碰到不符合就结束 List(1,9,2,4,5).partition(_<3) // (List(1, 2),List(9, 4, 5)),扫描所有 splitAt // (List(1, 3),List(5

scala学习手记16 &ndash; scala中的static

前面两节学了scala的对象和伴生对象,这两个在使用的时候很有些java的静态成员的意思. scala中没有静态字段和静态方法.静态成员会破坏scala所支持的完整的面向对象模型.不过可以通过伴生对象实现对scala的类一级的操作. 回过头来再看一遍那个Marker的例子,略做了一些调整: class Marker private(val color: String) { println("Creating " + this) override def toString(): Stri

scala学习手记2 - scala中的循环

先来看一段Java中的循环: for (int i = 1; i < 4; i++) { System.out.print(i + ","); } 毫无疑问,scala可以让这个循环更加简洁.根据上一节中的内容,没有必要显示指定变量i的类型,我们甚至不需要声明这个变量.其次输出的语句也可以更加简洁一些,在scala中可以直接使用println()这个方法输出字符串.最后scala的循环结构也是非常的轻量级.好了,可以看一下代码了: for (i <- 1 to 3) { p

第85讲:Scala中For表达式的强大表现力实战

今日[DT大数据梦工厂视频]<第85讲:Scala中For表达式的强大表现力实战>51CTO视频:http://edu.51cto.com/lesson/id-71503.html(DT大数据梦工厂scala的所有视频.PPT和代码在百度云盘的链接:http://url.cn/fSFPjS)85讲 scala for 表达式的强大表现力高阶函数的行为 指定了对数据 处理 的细节 .case class Person(name:String,isMale:Boolean,children:Per

第81讲:Scala中List的构造和类型约束逆变、协变、下界详解

今天来学习一下scala中List的构造和类型约束等内容. 让我们来看一下代码 package scala.learn /** * @author zhang */abstract class Big_Data class Hadoop extends Big_Dataclass Spark extends Big_Data object List_Constructor {  def main(args:Array[String]){    val hadoop = new Hadoop ::

Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/pR_4sY0cJLs/优酷:http://v.youku.com/v_show/id_

scala中的表达式

scala中的表达式是有值的, 所以可以把表达式当做参数来传递, 那么接受表达式的形参定义一般是: block: =>Unit   , 没有形参,返回类型Unit spark中的这个代码很经典,可以传递一个代码块给函数: def tryOrIOException(block: =>Unit){ try{ block } catch { case e:IOException => throw e case NonFatal(t) => throw new IOException(t)

scala入门教程:scala中的面向对象定义类,构造函数,继承

我们知道scala中一切皆为对象,函数也是对象,数字也是对象,它是一个比java还要面向对象的语言. 定义scala的简单类 class Point (val x:Int, val y:Int) 上面一行代码就是一个scala类的定义: 首先是关键字class 其后是类名 Point 类名之后的括号中是构造函数的参数列表,这里相当于定义了对象的两个常量,其名称分别为x,y,类型都是Int 上面的类和下面的类是一致的,不过更精简了. class Point (xArg:Int, yArg:Int)