[英]Changing kotlin extension function receiver JVM name
This is a general question. 这是一个普遍的问题。 Let's say I have an extension function written in kotlin which converts DP to PX and return a NonNull Int 假设我有一个用kotlin编写的扩展函数,它将DP转换为PX并返回一个NonNull Int
fun Int.toPx() { /** implementation */ }
The function in java will look something like this java中的函数看起来像这样
public int toPx(int $receiver) { /** implementation */ }
In my opinion the $receiver
makes the Java-interop feels generated and uninviting. 在我看来, $receiver
使得Java-interop感觉生成和不受欢迎。
I know that you can use the @JvmName
annotation with some combinations like @file:JvmName
to change the name in java. 我知道您可以使用@JvmName
注释和@file:JvmName
类的组合来更改java中的名称。
When i'm trying to use @JvmName
with the receiver
site target it says 当我试图将@JvmName
与receiver
站点目标一起使用@JvmName
,它说
"This annotation is not applicable to target type usage
and use site target @receiver
" “此注释不适用于目标type usage
并使用站点目标@receiver
”
Is there a way to overcome that and change the name of the receiver and if not what is the best alternative. 有没有办法克服它并改变接收器的名称,如果不是最好的选择。
@JvmName
can only be applied to functions, property accessors and top-level package facades for files. @JvmName
只能应用于文件的函数,属性访问器和顶级包外观。 Parameter names are not supported. 不支持参数名称。
Basically, you can define two functions, one taking a simple parameter and another one with receiver: 基本上,您可以定义两个函数,一个采用简单参数,另一个采用接收器:
fun toPx(value: Int) { /* implementation */ }
fun Int.toPx() = toPx(this)
But, expectedly enough, this won't compile because the two functions would have the same JVM signatures. 但是,预计足够,这将无法编译,因为这两个函数将具有相同的JVM签名。 So, to disambiguate them, add @JvmName("...")
to the extension and (optionally) mark the extension as inline
: 因此,要消除它们的歧义,请将@JvmName("...")
添加到扩展名,并(可选)将扩展名标记为inline
:
fun toPx(value: Int) { /* implementation */ }
@JvmName("toPxExtension") @Suppress("nothing_to_inline")
inline fun Int.toPx() = toPx(this)
To hide the extension function from Java, you can also annotate it with @JvmSynthetic
. 要从Java隐藏扩展函数,您还可以使用@JvmSynthetic
对其进行@JvmSynthetic
。
The downside of this solution is the top-level function toPx
leaking into the IDE completion scope of the files that see the package. 这个解决方案的缺点是顶层函数toPx
泄漏到查看包的文件的IDE完成范围。
The parameter name is only relevant in Java regarding documentation (as a method signature hint in the IDE, when you call a method). 参数名称仅在Java中与文档相关(作为IDE中的方法签名提示,当您调用方法时)。 Unlike in Kotlin, it is never part of the calling code. 与Kotlin不同,它从不是调用代码的一部分。
If you define extension methods on existing types, I've found that a good approach is to name the file in a way that describes the receiver. 如果您在现有类型上定义扩展方法,我发现一个好方法是以描述接收器的方式命名文件。 While this doesn't matter for Kotlin (as extension methods will be called without the file name), it does for other JVM languages. 虽然这对Kotlin无关紧要(因为扩展方法将在没有文件名的情况下调用),但它适用于其他JVM语言。 Thus, the receiver type/meaning is not expressed by the parameter name, but by the class name. 因此,接收器类型/含义不是由参数名称表示,而是由类名表示。
You're already aware of @file:JvmName
, so use it to your advantage: 你已经知道了@file:JvmName
,所以使用它有利于你:
@file:JvmName("Ints")
fun Int.toPx() { ... }
In Kotlin: 在Kotlin:
val value = 328
val px = value.toPx()
In Java, the code is very close to the Kotlin counterpart: 在Java中,代码非常接近Kotlin对应的代码:
int value = 328;
Pixel px = Ints.toPx(value);
Can of course be a longer name such as IntExtensions
if that helps readability. 当然可以是更长的名称,如IntExtensions
如果这有助于可读性。
Note that in Kotlin, it is explicitly allowed to reuse the same class name in @file:JvmName
across multiple files, and the extensions functions will be combined in a single JVM class (see also here ). 请注意,在Kotlin中,明确允许在多个文件中的@file:JvmName
重用相同的类名,并且扩展函数将组合在一个JVM类中(另请参见此处 )。 You need the annotation @file:JvmMultifileClass
for this. 你需要注释@file:JvmMultifileClass
。
Thus, you could also have an Int
extension completely unrelated to pixels in another file, yet it would still end up in the same Java class Ints
. 因此,您还可以使Int
扩展与另一个文件中的像素完全无关,但它仍然会在同一Java类Ints
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.