谈谈Scala的抽取器(Extractor)
初次接触*抽取器(Extractor)这个概念,有点不好理解,可能是本人英语不过关。经过反复推敲,总算弄明白是什么一回事.
以下的讨论基于scala 2.8
还是从一个例子说起。 假设我们想验证一个字符串的格式是否符合邮件地址格式,如果是,提取它的用户部分和域名部分。比如给定字符串jack@163.com
, 经过测试发现符合邮件地址格式,然后提取出jack
和163.com
。一般做法是通过正则表达式进行匹配并提取相应的匹配组. 在Scala中,可以通过模式匹配实现。具体做法是,给一个对象(不妨叫obj)定义一个unapply
方法,且该方法必须返回Option[T]
类型; 在使用该对象与给定的参数(不妨叫selector)进行模式匹配时,会调用该对象的unapply方法; 调用unapply方法时会传入一个参数,该参数就是待匹配的参数(selector);匹配逻辑定义在unapply方法中,假如匹配成功,unapply方法返回Some[T]类型的对象, 否则返回None。Some()所包含的内容没有限制,但一般让它带回匹配的内容。 比如
object Email{def unapply(str: String): Option[(String, String)] = {val parts = str split "@"if (parts.length == 2) Some(parts(0), parts(1)) else None}
}val str = "jack@163.com"
str match{
case Email(username, address) => println("username: "+username+" address: "+addres);
case _ => println("this is not an email address ");
}
实际上str 与 Email 作模式匹配时 会被翻译成
Email.unapply(str) match{
case Some(username, address) => ...
case None => ...
}
所谓的extractor就是指含有unapply方法(或unapplySeq方法)的对象. 如果你只想检验该字符串是否为一个合法的邮件地址, 可以让unapply返回Boolean类型. 假如你希望过滤出邮件用户名不含有大写字母, 且是由重复的两部分组成的,比如coco@hotmail.com,你可以这样做:
object LowerCase{def unapply(name: String) = name.toLowerCase == name
}
object Twice{def unapply(s: String) : Option[String] = {val len = s.length /2 val half = s.substring(0, len);if (half == s.substring(len)) Some(half) else None}
}def userTwiceLower(s: String) = s match{ case Email(Twice(x @ LowerCase()), domain) => "match: "+ x + " in domain " + domaincase _ => "no mach"
}
userTwiceLower("coco@hotmail.com")
userTwiceLower("COco@hotmail.com")
userTwiceLower("ggd543@gmail.com")
当然你完全可以用正则表达式实现,但我相信那样做要复杂得多,而且缺乏灵活性。
假如你需要匹配或分解selector的多个组成部分, 而事先又不确定有多少,你可以使用unapplySeq
方法。unapplySeq
的用法跟unapply差不多,但必须返回Option[Seq[T]]类型。 比如我需要把ggd543@gdut.edu.cn的邮件域名各组成部分提取出来, cn, edu, gdut。 下面的例子匹配邮件用户名前缀为stu_ ,域名为cn的邮件地址:
object Email { ... }
object Domain{def unapplySeq(whole: String) : Option[Seq[String]] ={Some(whole.split("\\.").reverse);}
}object StuPrefix{def unapply(name: String) = name.startsWith("stu_")
}
def isStuCnMail(str: String) = str match{case Email(StuPrefix(), Domain("cn", _*)) => truecase _ => false
}
isStuCnMail("stu_jack@gdut.edu.cn")
当然使用unapply也可以,只是写法上没有那么直观. 其实Scala的Array, List等集合类实现了unapplySeq方法,使得我们可以这么写:
val Array(a,b,c,d) = Array(1,2,3,4)
val List(head, tail @ _ *) = List(1,2,3,4)
虽然看起来有点像Constructor Pattern.
如果你对extractor的理解仅仅停留在能实现用户自定义的模式匹配的技术层面上,那就太肤浅了。 我认为Scala提供抽取器(Extractor) 这种语法糖的目的在于,将数据模型和视图逻辑分离,或者说它充当了类似于适配器那样的角色, 而且是一种比较函数式的做法。
至于在实际编程中应该采用case class还是extractor进行模式匹配,官方给出的建议是:
- 如果你定义的数据结构或接口仅限于内部使用,而且不会经常变更,推荐使用case class
- 如果接口是给别人用,或面对的是一些遗留类, 推荐使用extractor.
- 如果你拿不准,可以先采用case class,当发现case class 不能适应需求的变化时 ,再改用extractor。使用case class进行模式匹配有一个好处,就是编译器能优化你的代码。假如你的case class是继承自一个封装类(被seal关键字修饰的类),那么编译器还可以对你的match表达式进行检查,并提醒你是否遗漏了某些可能的情况。而extractor比较灵活,能实现你希望的匹配逻辑,但运行效率上比case class要慢。
谈谈Scala的抽取器(Extractor)相关推荐
- 2021年大数据常用语言Scala(三十五):scala高级用法 提取器(Extractor)
目录 提取器(Extractor) 定义提取器 提取器(Extractor) 我们之前已经使用过scala中非常强大的模式匹配功能了,通过模式匹配,我们可以快速匹配样例类中的成员变量.例如: // ...
- 3d立体相册特效html网页代码_新闻类网页正文通用抽取器
项目起源 开发这个项目,源自于我在知网发现了一篇关于自动化抽取新闻类网站正文的算法论文--<基于文本及符号密度的网页正文提取方法> 这篇论文中描述的算法看起来简洁清晰,并且符合逻辑.但由于 ...
- 网页详情页通用提取——通用新闻网站正文抽取器
页面标题的爬取 以及页面text的爬取 python 新闻网站通用爬虫 GNE(GeneralNewsExtractor)是一个通用新闻网站正文抽取模块,输入一篇新闻网页的 HTML, 输出正文内容. ...
- NLP工具——自制zero-shot事件抽取器
NLP工具--自制zero-shot事件抽取器 0. 简介 1. 抽取全部潜在的事件 2. 抽取特定类型的事件 3. 结语 0. 简介 在事件抽取任务中,数据的获取是一件非常关键工作,由于数据标注的成 ...
- 【 FPGA 】FIR 滤波器之半带抽取器(Half-band Decimator)
之前有篇博文讲了半带FIR滤波器:半带FIR滤波器 其幅频响应如下: 脉冲响应如下: 而今天所要讲的是半带抽取器,半带抽取器是一个多相滤波器,它嵌入了输入信号的2- 1下采样.图3-30显示了结构. ...
- 多相抽取器实现及matlab示例
1. 概要 多相滤波器并不是指具有某种特性的时域或者频域特性的滤波器,它指的是一种滤波器实现的结构,常用于多速率数字信号处理(multi-rate digital signal processing) ...
- 第二季:7.怎么查看服务器默认的垃圾收集器是那个?生产上如何配置垃圾收集器的?谈谈你对垃圾收集器的理解?【Java面试题】
第二季:7.怎么查看服务器默认的垃圾收集器是那个?生产上如何配置垃圾收集器的?谈谈你对垃圾收集器的理解?[Java面试题] 前言 推荐 7.怎么查看服务器默认的垃圾收集器是那个?生产上如何配置垃圾收集 ...
- 如何用java编写一个花名随机抽取器
2020博客之星年度总评选进行中:请为74号的狗子投上宝贵的一票! 我的投票地址:点击为我投票 文章目录 一.程序效果 二.需要用到的包 三.代码 1.相关实例对象,所以对象均为全局对象 2.建立窗体 ...
- scala基础之提取器extractor
一 apply & unapply方法 apply方法我们已经非常熟悉了,它帮助我们无需new操作就可以创建对象,而unapply方法则用于析构出对象,在模式匹配中特别提到,如果一个类要能够应 ...
- Scala 提取器(Extractor)
提取器: 1.其实伴生对象有两个方法 ,A: apply B : unapply方法 2.我们使用apply方法来构造我们的一个对象, 不需要使用new关键字了.对吧. 3.我们使用unapp ...
最新文章
- 从json到抽取关键词
- 2204 Problem A(水)
- python基本数据类型的结构和使用方法
- 以HANA为核心 SAP实时数据平台详解
- leetcode刷题:最大子序积
- A simple BBS demo including(CRUD) - 1
- JTAG接口针脚定义及含义
- 相机快门和曝光时间的确定
- Excel的官方网站
- 花式二维码生成,提供了 6 种样式
- OPPO、一加将在德国禁售?原来是被“专利流氓”诺基亚盯上了!
- Coder HDU - 4288
- shell统计网卡流量
- 习题 8.21 用指向指针的指针的方法对n个整数排序并输出。要求将排序单独写成一个函数。n个整数在主函数中输入,最后在主函数中输出。
- 【网络工程】9、实操-万达酒店综合项目(三)
- 未来五年,不懂人工智能的程序员不会被淘汰
- python怎么让电脑说话_懒人专用的奇淫技巧,用Python实现炫酷的语音操作电脑
- Mac休眠之后唤醒时无法使用鼠标
- Windows10安装ObjectARX 2021 Wizard无法创建项目的解决方案
- 《Clair二次开发指南2——analyze-local-images源码剖析》
热门文章
- 关于ksps(A/D转换速率单位)
- RTKlib软件学习(观测文件与星历文件读取)
- 汇编指令——bic(位清除)、orr(位或)、eor (异或)
- 创建局域网Git服务器
- antd tooltip 修改样式
- 江苏成人高考考前注意事项
- Android出现Could not initialize class com.android.sdklib.repository.AndroidSdkHandler的解决方法
- 【Python爬虫】新手入门案例教学(一):爬取豆瓣电影排行有关信息
- Ubuntu论坛的开通
- 85人教版高中英语第一册第十一课 AT A TAILOR'S SHOP