一篇入门 — Scala 宏

 

前情回顾

上一节, 我简单的说了一下反射的基本概念以及运行时反射的用法, 同时简单的介绍了一下编译原理知识, 其中我感觉最为的地方, 就属泛型的几种使用方式了.
而最抽象的概念, 就是对于符号和抽象树的这两个概念的理解.

现在回顾一下泛型的几种进阶用法:

  • 上界 <:
  • 下界 >:
  • 视界 <%
  • 边界 :
  • 协变 +T
  • 逆变 -T

现在想想, 既然已经有了泛型了, 还要这几个功能干嘛呢? 其实可以类比一下, 之前没有泛型, 而为什么引入泛型呢?

当然是为了代码更好的服用. 想象一下, 本来一个方法没有入参, 但通过参数, 可以减少很多相似代码.

同理, 泛型是什么, generics. 又叫什么, 类型参数化. 本来方法的入参只能接受一种类型的参数, 加入泛型后, 可以处理多种类型的入参.

顺着这条线接着往下想, 有了逆变和协变, 我们让泛型的包装类也有了类继承关系, 有了继承的层级关系, 方法的处理能力又会大大增加.

泛型, 并不神奇, 只是省略了一系列代码, 而且引入泛型还会导致泛型擦除, 以及一系列的隐患. 而类型擦除其实也是为了兼容更早的语言, 我们束手无策.
但泛型在设计上实现的数据和逻辑分离, 却可以大大提高程序代码的简洁性和可读性, 并提供可能的编译时类型转换安全检测功能. 所以在可以使用泛型的地方我们还是推荐的.

编译时反射

上篇文章已经介绍过, 编译器反射也就是在Scala的表现形式, 就是我们本篇的重点 宏(Macros).

Macros 能做什么呢?

直白一点, 宏能够

Code that generates code

还记得上篇文章中, 我们提到的AST(abstract syntax tree, 抽象语法树)吗? Macros 可以利用 compiler plugin 在 compile-time 操作 AST, 从而实现一些为所以为的...任性操作

所以, 可以理解宏就是一段在编译期运行的代码, 如果我们可以合理的利用这点, 就可以将一些代码提前执行, 这意味着什么, 更早的(compile-time)发现错误, 从而避免了 run-time错误. 还有一个不大不小的好处, 就是可以减少方法调用的堆栈开销.

是不是很吸引人, 好, 开始Macros的盛宴.

黑盒宏和白盒宏

黑盒和白盒的概念, 就不做过多介绍了. 而Scala既然引用了这两个单词来描述宏, 那么两者区别也就显而易见了. 当然, 这两个是新概念, 在2.10之前, 只有一种宏, 也就是白盒宏的前身.

官网描述如下:
Macros that faithfully follow their type signatures are called blackbox macros as their implementations are irrelevant to understanding their behaviour (could be treated as black boxes).
Macros that can't have precise signatures in Scala's type system are called whitebox macros (whitebox def macros do have signatures, but these signatures are only approximations).

我怕每个人的理解不一样, 所以先贴出了官网的描述, 而我的理解呢, 就是我们指定好返回类型的Macros就是黑盒宏, 而我们虽然指定返回值类型, 甚至是以c.tree定义返回值类型, 而更加细致的具体类型, 即真正的返回类型可以在宏中实现的, 我们称为白盒宏.

可能还是有点绕哈, 我举个例子吧. 在此之前, 先把二者的位置说一下:

2.10

  • scala.reflect.macros.Context

2.11 +

  • scala.reflect.macros.blackbox.Context
  • scala.reflect.macros.whitebox.Context

黑盒例子

import scala.reflect.macros.blackbox  

                    
                
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信