在Lisp语言中,macro是一个神器,可以“动态的生成代码”,然后被执行,这种方式给到Lisp无限的表达能力。除Lisp之外,很少有语言支持Macro这个特性,我记得 GWT之中曾经有一个类似的Generator的概念,可以在编译期间提供一定的代码生成能力(GWT Project),很多GWT的高级特性都是通过这个语言特性而得以实现的,譬如:

  • UiBinder 可以实现申明式的 UI 开发。

  • ImageBundle 简单的实现很多图片的聚合,从而减少round-trip,提高网页装载速度。

Scala自2.10开始尝试支持macro编程,2.11基本步入”成熟“阶段,2.12中基本稳定,不过,在最新的路线图中,Scala之父,Martin再次表现了将在未来的scala版本(Dotty)中重新设计macro,采用基于scalameta的一套编译器“中立”的元信息模型,试图让macro变得更简单、容易。因此,尝试 macro,目前仍然具有很大的风险性,或许随着scala语言的未来版本,现有的macro也需要重新迁移、实现。

What is Macro?

简而言之,macro就是让你的代码具备有生成代码的能力,最简单的macro可以算上 C/C++ 的 ##define, 最早的 C 程序员就广泛的使用 define 来生成代码。(严格意义上,C的define并不算是 macro)

Why using Macro?

程序员喜欢写有挑战的代码,而肯定不喜欢 Copy & Paster,或者甚至连Copy Paste都算不上的重复性代码,一个很简单的例子,就是Java程序员都最熟悉的如下代码:

public class User {	
 private String name;
 private int age;
 public String getName(){ return this.name;}
 public void setName(String name){ this.name = name;}
 public int getAge(){ return this.age; }
 public void setAge(int age){ this.age = age; }
 public String toString(){ return "name:" + name + "/age:" + age;}  public int hashCode(){ return name.hashCode ^ age;}
 public boolean equalus(Object other){ return ......}
}

这段代码是非常有Java风格的一段代码,每一个Java程序员都很熟悉,这据说是一种设计模式,叫做”JavaBeans”, 这个模式有很多的延续:

  • 基本上每个IDE,都会有一个工具来帮你自动的生成 getter, setter, toString, hashCode等工具

  • 有一个 Lombok 的开源项目,帮你来生成这些代码。

  • scala 经常用 case class User(name:String, age: Int)来鄙视Java

  • Kotlin 经常用 data class User(val name: String, val age: Int)来鄙视Java

这是一个很好的案列:

  • 这段代码的“干货”很少,用一段为代码data class User(val name: String, val age: Int就可以表述清楚的东西,我们却需要啰啰嗦嗦的写一大段代码。没有程序员喜欢这种差事,除非,老板真的是按代码行数付工资的。

  • Lombok可以让你编写很少的代码,他来负责生成剩下的代码。

  • Eclipse/JetBrains,可以让你写少量的代码,他来负责生成剩下的代码。

  • Scala/Kotlin这两个编译器,可以让你写少量的代码,他来负责生成剩下的代码。

当我们只需要写最为”核心“的那一步代码,而剩下的代码,完全可以按照一个模式去自动生成时,我们的工作效率就大幅度提升了,而言,Less is more,更少的代码就意味着更快速的代码阅读、评审,更少的BUG,这一切,都会带给程序员更大的幸福感。

实际上,还有一种方式,也可能是最好的方式,就是利用macro,来帮你生成代码。当然,要这门语言,支持macro。从目前的情况来看,支持macro的语言还是非常有限的。scala作为学术派的代表,很有幸可以提供macro的能力。

When to using Macro?

记得在一本Clojure的书中说过什么时候可以使用Macro?

  • 如果你可以使用普通的函数实现,不要用macro

  • 如果你可以用其他方式实现,不要用macro

  • 实在找不到办法,尝试一下macro。

其实所有的一切,都是在于Macro的复杂性。如果说Clojure代码有如天书,那么,去生成天书的macro代码,就更是天书中的天书了。 这个放到Scala中,只会变得更为复杂,原因无二:Scala有一个非常复杂的类型体系,而Macro中你需要和这个无比复杂的类型体系打交道。所以,如果你对Scala的了解程度还不够深入的话,Macro也会是无从下手的。不过,这也是一个不错的试金石,如果你想说你对scala的了解程度很好的话,那么不妨挑战一下Macro。这绝对是一个既复杂,但又超级强大的工具。Macro的强大,有的时候,是无敌的,这些特性,只能在Macro中完成,你没有更好的被的办法。

How can Macros Do?

在本篇文章中,我不准备介绍 How to writing Macro?这个我会尝试在后续的文章中介绍,我会先介绍使用 macro,我们可以做些什么?

  • 更有效的日志性能。我们经常告诫,不要让日志影响性能:

if(logger.isDebugEnabled)
logger.debug("message is heavy in business: ");

为什么不能够直接用如下的代码来替代呢?logger.debug(message),既满足性能的需求,又简洁呢? Macro Can

  • 编译时期进行更好的语法检查。

"\d+".r.test("1234")复杂的正则表达式,往往需要复杂的调试工作,如果编译器能帮助我检查语法错误,相信可以让代码开发变得更为简单。其实,除了正则表达式,我们还可以检查原代码中的日期常量、时间常量等,当然,如果在做一下优化,自动的将复杂的字符串常量预编译为构造值,可能还会获得更好的性能。Macro Can

  • 是否可以在编译时,对我们的SQL语句,自动的进行语法检查?更好的,链接到一个数据库,进行预处理检查,看看是否有错误的表名、字段名拼写?是否有语法性的错误?早期的4gl语言,就有这个特性,还是很实用的。

    Macro Can

  • 为我们的数据对象(Case ClassData Class)自动生成 toJSON, toXML, toProtobuf, toThrift等工具方法。反射是一种方式,所以有fast-son, fast-xml等框架?有没有可能有比fast-jsonfast-xml更加fast的方式呢?

    有的,Macro Can

  • 还能干什么?更为一般的,如果你要实现功能抽象成最小化的一个Core,然后你告诉一个程序员,如何实现剩下的功能,例如,如何编写gettersettertoString方法,让他来帮你实现代码。那么,你可以用 Macro 来直接完成,不再需要一个程序员的工作。这个也算是 AI 的一个近似值了把。

    Macro can write code for You

结合Scala的implicit,macro有很强大的功能,我会结合我的开源框架 scala-sql 应用的 macro 特性,给你继续Scala的神奇Macro之旅。

参考:

神奇的Scala Macro之旅(二)- 一个实例

转自:神奇的Scala Macro之旅

神奇的Scala Macro之旅(一)- 什么时候用宏的更多相关文章

  1. 神奇的Scala Macro之旅(四)- BeanBuilder

    在Java开发中,经常会有一个需求,将一个 Bean 复制到另外一个 Bean,尤其是在后台分层的场景下,在不同的层之间传递信息,经常需要进行 这样的一个对象复制工作,类似于: val source: ...

  2. 神奇的Scala Macro之旅(三)- 实际应用

    在上一篇中,我们示范了使用macro来重写 Log 的 debug/info 方法,并大致的介绍了 macro 的基本语法.基本使用方法.以及macro背后的一些概念, 如AST等.那么,本篇中,我们 ...

  3. 神奇的Scala Macro之旅(二)- 一个实例

    优化的日志方式 package macros_demo import scala.language.experimental.macrosimport org.slf4j._import scala. ...

  4. 神奇的Bank系统之旅哦

        奋斗不能等待,我们不能等到垂暮之年再去“全力以赴”.让我们从现在开始,为理想而努力,为人生而拼搏.精诚所至,金石为开,相信奋斗会让我们的青春之花绽放得更加绚烂,让我们的人生之路走下来不留遗憾. ...

  5. Scala开启之旅

    嘿嘿,公司最近需要测试SPARK性能,赶上了.. 那LUA之后,SCALA也简单看看,,, 其实,我三月时买了本129元的SPARK的书,,全国只那一本哈. package com.hengheng. ...

  6. Scala Macros - 元编程 Metaprogramming with Def Macros

    Scala Macros对scala函数库编程人员来说是一项不可或缺的编程工具,可以通过它来解决一些用普通编程或者类层次编程(type level programming)都无法解决的问题,这是因为S ...

  7. scala 宏

    Scala开发团队正在将实验版宏指令加入到即将发行的2.10版中.Scala宏指令提供了编译时元编程的高级形式.Scala宏网站描述道: “宏指令显著简化了代码分析和代码生成,这使得它们成为处理大量现 ...

  8. 构造Scala开发环境并创建ApiDemos演示样例项目

    从2011年開始写Android ApiDemos 以来.Android的版本号也更新了非常多,眼下的版本号已经是4.04. ApiDemos中的样例也添加了不少,有必要更新Android ApiDe ...

  9. Scala环境(集成idea)

    1 语言介绍 他已经出生15年了,就像明星一样,谁都不可能一开始就人气爆棚粉丝无数,得慢慢混. 据说这家伙已经威胁到了Java的地位,我当时也是被这句话惊到,才毅然决然的认识了他.目前也正在努力学习中 ...

随机推荐

  1. log4j2.xml全配置文件

    可以参考如下配置 <?xml version="1.0" encoding="UTF-8"?> <!--日志级别以及优先级排序: OFF &g ...

  2. 第三方支付设计——账户体系

    第三方支付架构设计之-帐户体系 一,      什么是第三方支付?         什么是第三方支付?相信很多人对这个名字很熟悉,不管是从各种媒体等都经常听到,可以说是耳熟能熟.但,如果非得给这个名词 ...

  3. mapreduce shuffle 和sort 详解

        MapReduce 框架的核心步骤主要分两部分:Map 和Reduce.当你向MapReduce 框架提交一个计算作业时,它会首先把计算作业拆分成若干个Map 任务,然后分配到不同的节点上去执 ...

  4. Python 内置的一些高效率函数用法

    1.  filter(function,sequence) 将sequence中的每个元素,依次传进function函数(可以自定义,返回的结果是True或者False)筛选,返回符合条件的元素,重组 ...

  5. Flask入门之Pycharm写Hello Word

    在这里记录整理Flask入门的笔记! 今天讲讲使用Pycharm写一个Hello World 前提是已经安装好Pycharm,安装过程很简单,这里不赘述. 只放两个可以提供注册码的网站: Intell ...

  6. [ SSH框架 ] Struts2框架学习之四(自定义拦截器)

    一.Struts2的拦截器 1.1 拦截器概述 拦截器,在AOP( Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.拦截 ...

  7. mac下nginx安装

    一.安装 Nginx 终端执行: brew search nginx brew install nginx 当前版本 1.10.2,通过brew可以把nginx需要的pcre,openssl,zlib ...

  8. API Gateway性能比较:NGINX vs. ZUUL vs.Cloud Gateway vs. Linkerd[译]

      2018-03-04 15:07 联发科的反思 前几天拜读了 OpsGenie 公司(一家致力于 Dev & Ops 的公司)的资深工程师 Turgay elik 博士写的一篇文章(链接在 ...

  9. 为何没有asia/beijing时区?

    Asia/Beijing 这个时区是消失了么? 大约1小时 ago @tinyfool 对啊,我就奇怪为什么北京时间就要用上海和成都... 大约1小时 ago @tinyfool @CatChen我所 ...

  10. XML解析的四种方法 建议使用demo4j解析 测试可以用

    https://www.cnblogs.com/longqingyang/p/5577937.html 4.DOM4J解析  特征: 1.JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功 ...