我正在使用Java API,现在已将其转换为 multiplatform Kotlin。它曾经使用java.lang.Optional
作为许多呼叫的返回类型。我知道这是not the idiomatic Kotlin-way(请参阅discussion),但这是一个现有的API,可选的保持符(对于面向Java的客户端,这也不是 bad 的选择)。我的问题是如何?
注意:该代码只需要return Optional.of(x)
或return Optional.empty()
到外部API。任何内部使用都将被清除。
expect
/actual
/typealias
来使用 real Optional
类??
后缀的情况)答案 0 :(得分:1)
在这一点上,Kotlin不允许通过使用带有匹配的actual typealias
声明的Java类来为带有companion object
的期望类提供static
。请关注此问题以获取更新:KT-29882。
现在,您可以通过在预期的Optional
类之外分别声明工厂函数来解决该问题,如下所示:
expect class Optional<T : Any> {
fun get(): T
fun isPresent(): Boolean
/* ... */
}
expect object Optionals {
fun <T : Any> of(t: T): Optional<T>
fun empty(): Optional<Nothing>
}
不一定必须是object
,您可以使用顶级功能。
然后,在JVM上,您必须为actual typealias
类提供一个Optional
,并另外为Optionals
对象提供简单的实际实现:
actual typealias Optional<T> = java.util.Optional<T>
actual object Optionals {
actual fun <T : Any> of(t: T): Optional<T> = java.util.Optional.of(t)
actual fun empty(): Optional<Nothing> = java.util.Optional.empty()
}
对于不为非JVM平台提供实现,我怀疑是否可行,因为这将需要将Optional
用法进行一些非平凡的编译时转换,仅转换为可空类型。所以你想要这样的东西:
actual typealias Optional<T> = T?
现在是一个错误:
类型别名扩展为
T?
,它不是类,接口或对象
因此,您实际上需要一个非JVM实现。为了避免为每个非JVM目标复制它,您可以声明一个自定义源集并将其与特定于平台的源集链接,以便它们从那里获取实现:
build.gradle.kts
kotlin {
/* targets declarations omitted */
sourceSets {
/* ... */
val nonJvmOptional by creating {
dependsOn(getByName("commonMain"))
}
configure(listOf(js(), linuxX64())) { // these are my two non-JVM targets
compilations["main"].defaultSourceSet.dependsOn(nonJvmOptional)
}
}
}
然后,在此自定义源集中(例如,在src/nonJvmOptional/kotlin/OptionalImpl.kt
中),您可以为非JVM目标提供实际的实现。
在Github上,这是一个最小的项目示例,我在上面进行了实验:h0tk3y/mpp-optional-demo