神奇的Scala Macro之旅(一)- 何时用宏 神奇的Scala Macro之旅(二)- 一个实例

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

  • UiBinder 能够实现申明式的 UI 开发。android

  • 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)sql

 

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等工具json

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

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

  • 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之旅

相关文章
相关标签/搜索