提问人:Robert Elliot 提问时间:10/17/2022 最后编辑:Robert Elliot 更新时间:10/19/2022 访问量:410
是否可以使用 Groovy 中的命名参数(包括“copy”)调用 Kotlin 函数?
Would it be possible to call a Kotlin function with named parameters from Groovy (including `copy`)?
问:
Context - 带有 Spock/Groovy 测试的 Kotlin 代码库。
在我的 Groovy 测试中,使用名称调用带有命名参数的 Kotlin 函数会很方便。我特别将其用于实体的测试构建器。
我希望能够使用 Groovy 中的参数名称调用它们。
因此,鉴于这个 Kotlin:
data class User(
val id: Id,
val name: String,
val emailAddress: String,
)
fun buildUser(
id: Id = randomId(),
name: String = randomName(),
emailAddress: String = randomEmailAddress(),
): User
我希望能够写出这个时髦的东西:
User user = buildUser(
name: 'My name'
)
感觉这应该是可能的;要么在 Kotlin 端使用编译器插件,使用采用 的版本重载方法,要么通过 Groovy 端的 AST 转换。有人这样做过吗?buildUser
Map
这也可能允许以相同的方式在 上调用该方法:copy
data class
User user = buildUser()
User userWithDifferentEmailAddress = user.copy(emailAddress: '[email protected]')
理想情况下,IntelliJ IDEA 会充分了解它,以便能够尊重重命名参数并从调用站点参数名称导航到接收站点参数,但这可能要求太多......
编辑 - 查看反编译的 Kotlin,它会创建以下方法:
public static User buildUser$default(Id var0, String var1, String var2, int var3, Object var4) {
// uses var3 as a flag to indicate which fields were provided by the caller
}
public static User copy$default(User var0, Id var1, String var2, String var3, int var4, Object var5) {
// uses var4 as a flag to indicate which fields were provided by the caller
}
所以应该可以争吵 Groovy 来称呼他们,我认为......
答:
0赞
Leonard Brünings
10/19/2022
#1
我只能提供部分解决方案。通过 Groovy 的变换,您可以在 Groovy 中像这样声明您的工厂函数。@NamedVariant
@NamedVariant
User buildUser(
Id id = randomId(),
String name = randomName(),
String emailAddress = randomEmailAddress()) {
new User (id, name, emailAddress )
}
它将生成一个重载,该重载采用映射或参数,因此您可以按照描述的方式使用它们。
至于在普通的时髦中无事可做。copy
您可以尝试编写 AST 转换,但您将依赖于 kotlin 编译器实现来了解如何生成方法以及如何设置标志。我认为尝试生成复制行为的自定义 groovy 扩展函数会更容易。查看扩展模块
评论
buildUser(name: 'My name')
- 你有没有尝试过Groovy的相同语法?有什么错误吗?groovy.lang.MissingMethodException: No signature of method: static foo.ExperimentKt.buildUser() is applicable for argument types: (LinkedHashMap) values: [[name:My name]] Possible solutions: buildUser(foo.Id, java.lang.String, java.lang.String)
@NamedVariant
@NamedVariant User buildUser(Id id = randomId(), String name = randomName(), String emailAddress = randomEmailAddress()) { new User (id, name, emailAddress )}