正确地使用 Kotlin 的 internal

2020-02-20 13:15:14 浏览数 (3)

Kotlin 的 internal 是一个比较有用的访问控制关键字,特别是当你开发一些 SDK 给别人用时,有些类的 API 只能为 public 却又不想让外部访问到你就会发现 internal 有多么有用了 —— 只是实际情况有点儿事与愿违,internal 关键字修饰的成员在被编译成 jar 之后,Java 仍然可以无所顾忌的访问这些成员,除了名称有些奇怪。这可怎么办。小伙伴们就炸了,于是一向特立独行的冰冰给出了自己的方案。


Kotlin 的 internal 被定义为 "只有这个模块可以调用" 却在被打包为 jar 后可以被 Java 代码视为 public 调用, which 被广为诟病。 那么就让我们来看看怎么解决这个问题吧。

这个问题其实很好解决,不知道为什么之前都没有人发现。 方法就是欺负 Java 语法不行。

比如说我们有这个 Kotlin 的 internal 函数。

代码语言:javascript复制
internal fun zython() {
}

如果 Kotlin 编译器能知道有 Java 代码跨模块调用了它,那么 Kotlin 编译器会说编译不过。 但是如果把这个函数的定义打包进一个 jar 然后完全脱离 Kotlin 编译器的怀抱,那么就鸡寄了, Java 就可以为所欲为。

那么我们应该怎么惩戒那些为所欲为的垃圾 Java 厨呢。

方法一

我们可以使用 @JvmName 这个神器。

这个注解可以让 Kotlin 编译器改变生成的函数在字节码里面的名字,但是在代码里面依然可以使用原本的名字。 那么,我们使用 @JvmName ,给它一个 Java 写不出来的函数名就好了。

比如,在函数名里面加一个空格。

代码语言:javascript复制
@JvmName(" zython")
internal fun zython() {
}

或者你是 Haskell 厨,那么你可以骚一点

代码语言:javascript复制
@JvmName("{-# LANGUAGE Zython #-}")
internal fun zython() {
}

这样的话,调用这个函数的权利就被 Kotlin 独占了,因为如果在 jar 里面引用的话,函数名就是 @JvmName 的参数, which Java 根本写不出来,只有 Kotlin 可以用。

然后我们的 internal 修饰符就达到了效果。

方法二

我们可以劲爆一点,直接就在 Kotlin 里面使用骚命名。

我们知道, Kotlin 允许使用 ` ` 把一个不合法的标识符强行合法化,当然本身是合法的也能用。 一般我们都只用于关键字冲突的情形,可你们一定没想到有这种妙用吧。

我们依然可以普普通通地使用加空格之类的欺负 Java 的方法:

代码语言:javascript复制
internal fun ` zython`() {
}

或者你是 Haskell 厨,那么你可以骚一点

代码语言:javascript复制
internal fun `{-# LANGUAGE Zython #-}`() {
}

这都是支持的。 比如我在我的一个个人项目里的某个文件就用了这种操作。 当然我不是为了 internal ,只是为了好看。

结束

顺带一提,刚刚在复制这篇文章的内容的时候,谷歌翻译把我的代码给翻译出来了, internalfun 变成了 "内部的乐趣",笑出声。

我说完了。

0 人点赞