1.2 元编程的基本概念
元编程这个词看上去有些晦涩。元字的意思较多,包含开端、根源等诸多含义。本节将简单介绍元编程的定义和分类。
1.2.1 元编程的定义
元编程(Meta Programming)就是以程序为数据的编程。这意味着元编程往往是以访问和修改程序本身为目的的。其中,编写元程序的语言被称为元语言,被操作的语言则被称为目标语言。
元编程与普通编程的区别在于处理的对象不同。大家可能已经有过很多元编程的实践,例如Java/Kotlin的反射、APT(Annotation Processing Tool,注解处理器)、代码规范检查工具等。
元编程的概念不吓人,但也不是没有门槛。不管是什么类型的程序,程序设计者都需要在充分了解其业务需求背景和数据结构之后才能够将程序逐步落地。元编程也是如此,我们需要对目标语言的元数据有一定的认识,才能够设计出符合预期的元程序。
Kotlin是一门支持多平台的编程语言,因而相关的元数据种类也较为丰富。本书将在第2章专门对Kotlin的元数据进行介绍,这将是我们后续实践Kotlin元编程的重要基础。
1.2.2 元编程的分类
Kotlin支持两种不同阶段的元编程,即运行时元编程和编译时元编程。
运行时元编程通常是指运行时反射。我们可以使用反射在目标程序运行时修改其程序结构的信息,控制函数的调用,实现一定程度上的动态能力。在Kotlin中,我们既可以使用Java反射,也可以使用Kotlin反射,反射相关的内容将在第3章详细介绍。
编译时元编程涵盖了程序从编写到编译的所有阶段。按照目标程序的形式,又可以将编译时元编程分为源代码处理、编译中间产物处理和编译产物处理。
Kotlin元编程的分类如图1-1所示。
图1-1 Kotlin元编程的分类
绝大多数情况下我们编写元程序是为了生成源代码。本书第4章会详细介绍源代码生成相关的内容,第5章介绍的符号处理器通常也是以生成源代码为目的的。
除了生成源代码以外,我们还可以通过编写元程序来实现对源代码的分析。有关程序静态分析的内容将在第6章展开讨论。
Kotlin编译器在编译过程中会产生一些中间代码,想要实现对中间代码的处理就需要借助编译器提供的扩展能力。我们将在第7章详细介绍Kotlin编译器插件(Kotlin Compiler Plugin),并在第9章对Jetpack Compose的编译器插件实现进行详细的剖析。
Kotlin对于符号处理的支持包括KAPT(Kotlin Annotation Processing Tool)和KSP(Kotlin Symbol Processing),二者均是基于Kotlin编译器提供的扩展能力实现的。我们将在第5章详细介绍Kotlin中与符号处理相关的内容,并在7.5节介绍符号处理器的实现原理。
编译产物的处理与对应平台的相关性很大,因此本书不打算对其展开重点讨论。不过,我们还是会在第10章中以AtomicFU框架为例,介绍如何对Kotlin JVM和Kotlin JS的编译产物进行处理。