跳到内容

代码与控制流

KotlinPoet 的大多数 API 使用不可变的 Kotlin 对象。还有构建器、方法链和可变参数,使 API 更易用。KotlinPoet 提供了 Kotlin 文件 (FileSpec)、类、接口与对象 (TypeSpec)、类型别名 (TypeAliasSpec)、属性 (PropertySpec)、函数与构造函数 (FunSpec)、参数 (ParameterSpec) 和注解 (AnnotationSpec) 的模型。

但是,方法和构造函数的主体没有被建模。没有表达式类、语句类或语法树节点。取而代之的是,KotlinPoet 使用字符串来表示代码块,并且您可以利用 Kotlin 的多行字符串使其看起来更美观

val main = FunSpec.builder("main")
  .addCode("""
    |var total = 0
    |for (i in 0..<10) {
    |    total += i
    |}
    |""".trimMargin())
  .build()

这会生成以下代码

fun main() {
  var total = 0
  for (i in 0..<10) {
    total += i
  }
}

还有额外的 API 来帮助处理换行、大括号和缩进

val main = FunSpec.builder("main")
  .addStatement("var total = 0")
  .beginControlFlow("for (i in 0..<10)")
  .addStatement("total += i")
  .endControlFlow()
  .build()

这个例子很蹩脚,因为生成的代码是常量!假设我们不想仅仅将 0 加到 10,而是希望操作和范围是可配置的。这是一个生成方法的方法

private fun computeRange(name: String, from: Int, to: Int, op: String): FunSpec {
  return FunSpec.builder(name)
    .returns(Int::class)
    .addStatement("var result = 1")
    .beginControlFlow("for (i in $from..<$to)")
    .addStatement("result = result $op i")
    .endControlFlow()
    .addStatement("return result")
    .build()
}

当我们调用 computeRange("multiply10to20", 10, 20, "*") 时,得到的结果如下

fun multiply10to20(): kotlin.Int {
  var result = 1
  for (i in 10..<20) {
    result = result * i
  }
  return result
}

生成方法的方法!而且由于 KotlinPoet 生成的是源代码而不是字节码,您可以通读它以确保其正确性。