跳到内容

%M 用于成员

与类型类似,KotlinPoet 为成员(函数和属性)提供了一个特殊的占位符,这在你的代码需要访问顶层成员和对象内部声明的成员时非常方便。使用 %M 来引用成员,将 MemberName 的实例作为占位符的参数传入,KotlinPoet 将自动处理导入

val createTaco = MemberName("com.squareup.tacos", "createTaco")
val isVegan = MemberName("com.squareup.tacos", "isVegan")
val file = FileSpec.builder("com.squareup.example", "TacoTest")
  .addFunction(
    FunSpec.builder("main")
      .addStatement("val taco = %M()", createTaco)
      .addStatement("println(taco.%M)", isVegan)
      .build()
  )
  .build()
println(file)

上面的代码生成以下文件

package com.squareup.example

import com.squareup.tacos.createTaco
import com.squareup.tacos.isVegan

fun main() {
  val taco = createTaco()
  println(taco.isVegan)
}

如你所见,也可以使用 %M 来引用扩展函数和属性。你只需要确保成员可以导入而不会发生简单名称冲突,否则导入将失败,并且代码生成器的输出将无法通过编译。不过,有一种方法可以解决这种情况 - 使用 FileSpec.addAliasedImport() 为冲突的 MemberName 创建别名

val createTaco = MemberName("com.squareup.tacos", "createTaco")
val createCake = MemberName("com.squareup.cakes", "createCake")
val isTacoVegan = MemberName("com.squareup.tacos", "isVegan")
val isCakeVegan = MemberName("com.squareup.cakes", "isVegan")
val file = FileSpec.builder("com.squareup.example", "Test")
  .addAliasedImport(isTacoVegan, "isTacoVegan")
  .addAliasedImport(isCakeVegan, "isCakeVegan")
  .addFunction(
    FunSpec.builder("main")
      .addStatement("val taco = %M()", createTaco)
      .addStatement("val cake = %M()", createCake)
      .addStatement("println(taco.%M)", isTacoVegan)
      .addStatement("println(cake.%M)", isCakeVegan)
      .build()
  )
  .build()
println(file)

KotlinPoet 将为 com.squareup.tacos2.isVegan 生成一个别名导入

package com.squareup.example

import com.squareup.cakes.createCake
import com.squareup.tacos.createTaco
import com.squareup.cakes.isVegan as isCakeVegan
import com.squareup.tacos.isVegan as isTacoVegan

fun main() {
  val taco = createTaco()
  val cake = createCake()
  println(taco.isTacoVegan)
  println(cake.isCakeVegan)
}

MemberName 和操作符

MemberName 也支持操作符,你可以使用 MemberName(String, KOperator)MemberName(ClassName, KOperator) 来导入和引用操作符。

val taco = ClassName("com.squareup.tacos", "Taco")
val meat = ClassName("com.squareup.tacos.ingredient", "Meat")
val iterator = MemberName("com.squareup.tacos.internal", KOperator.ITERATOR)
val minusAssign = MemberName("com.squareup.tacos.internal", KOperator.MINUS_ASSIGN)
val file = FileSpec.builder("com.example", "Test")
  .addFunction(
    FunSpec.builder("makeTacoHealthy")
      .addParameter("taco", taco)
      .beginControlFlow("for (ingredient %M taco)", iterator)
      .addStatement("if (ingredient is %T) taco %M ingredient", meat, minusAssign)
      .endControlFlow()
      .addStatement("return taco")
      .build()
  )
  .build()
println(file)

KotlinPoet 将导入扩展操作符函数并输出操作符。

package com.example

import com.squareup.tacos.Taco
import com.squareup.tacos.ingredient.Meat
import com.squareup.tacos.internal.iterator
import com.squareup.tacos.internal.minusAssign

fun makeTacoHealthy(taco: Taco) {
  for (ingredient in taco) {
    if (ingredient is Meat) taco -= ingredient
  }
  return taco
}