Kotlin即将推出伴生块与伴生扩展机制
我们正在对伴生机制进行扩展,以解锁新的代码模式并改善跨平台互操作性。本文将概述这些新功能,并提供初步的迁移指南。
伴生块与扩展
许多编程语言都提供了类成员或类型成员的概念——这些功能不属于类的某个特定值,而属于类本身。常量、工具方法和工厂方法通常属于此类。
此前,人们使用伴生对象来定义这些成员。从 Kotlin 2.5.0 起,你还可以使用实验性的伴生块,它在语法上非常接近,但在编译方面有深刻变化。
事实上,这些成员可能并不直接定义在类本身上。你还可以使用实验性的伴生扩展来为某个类型声明新的类成员,即使你并不控制该类型。
伴生块与扩展的设计克服了伴生对象带来的限制。首先,你可以为任何类或接口定义伴生扩展——无论你是否控制它,无论它最初来自 Kotlin 还是 Java,也无论它是否有伴生对象。
其次,其编译策略类似于其他平台上的静态成员。例如,在 JVM 上,伴生块会被编译为静态成员。这对 Kotlin Multiplatform 还有额外意义:你现在可以定义期望的伴生块成员,并使用包含静态成员的 Java 类来实现它们。
如果你想进一步了解这个即将推出的语言特性,相应的 KEEP 提案包含所有信息。
使用实验性伴生
伴生块和伴生扩展是 Kotlin 2.5.0 中的实验性特性。这意味着你需要传递一个额外的编译器标志才能使用该特性:
-Xcompanion-blocks用于允许伴生块。-Xcompanion-blocks-and-extensions用于同时允许伴生块和伴生扩展。
使用第二个特性会导致编译器生成预发布二进制文件,这意味着使用伴生扩展的库在该特性稳定之前可能无法作为依赖项被使用。此限制不适用于公开伴生块,不过此类块的使用者仍需要启用伴生块特性。
我的伴生对象怎么办?
这引出一个自然的问题:在拥有伴生块和伴生扩展的语言中,伴生对象扮演什么角色?这个问题有两个答案:
- 一方面,大多数伴生对象的用法更适合由伴生块来满足,因此新代码可能更倾向于使用后者而非前者。
- 另一方面,有少数用例只能由伴生对象来满足。例如,如果你的伴生需要实现某个特定接口,那么伴生对象是唯一选择,因为它们会编译为一个完整的类。
不过,并不需要迁移。伴生对象是 Kotlin 不可分割的一部分,对它们的支持完全有保障。
如果你更希望迁移到伴生块,在大多数情况下,移除 object 关键字就足够了——但请注意,项目以及任何依赖它的代码都需要重新编译。生态系统中的其他工具可能尚未为伴生块做好准备,尽管我们正在努力确保主要参与者尽快提供这一支持。