可选的 Kotlin 多平台支持
Kotlin multiplatform support for Optional
我正在使用 Java API 现在转换为 multiplatform Kotlin。它曾经使用 java.lang.Optional
作为许多调用的 return 类型。我知道这是 (see discussion) 但这是一个现有的 API,可选的保留(而且它不是 不好的 选择 Java-面向客户)。我的问题是 如何?
注:代码只需要return Optional.of(x)
或return Optional.empty()
到外部API。任何内部使用都将被清除。
- 我们如何使用
expect
/actual
/typealias
来使用真正的Optional
class可用时?
- 有没有办法避免在非 Java 目标上重新实现 fake 可选 class(即惯用地使用 nullable
?
后缀)
此时,Kotlin 不允许使用 Java class 为预期的 class 和 companion object
提供 actual typealias
匹配 static
声明。关注本期更新:KT-29882.
目前,您可以通过在预期 Optional
class 之外单独声明工厂函数来解决此问题,如下所示:
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 上,您必须为 Optional
class 提供 actual typealias
,另外,为 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?
现在是一个错误:
Type alias expands to T?
, which is not a class, an interface, or an object
所以你实际上需要一个非 JVM 实现。为避免为每个非 JVM 目标重复它,您可以声明一个自定义源集并 link 它与特定于平台的源集一起,以便他们从那里获得实现:
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
我正在使用 Java API 现在转换为 multiplatform Kotlin。它曾经使用 java.lang.Optional
作为许多调用的 return 类型。我知道这是
注:代码只需要return Optional.of(x)
或return Optional.empty()
到外部API。任何内部使用都将被清除。
- 我们如何使用
expect
/actual
/typealias
来使用真正的Optional
class可用时? - 有没有办法避免在非 Java 目标上重新实现 fake 可选 class(即惯用地使用 nullable
?
后缀)
此时,Kotlin 不允许使用 Java class 为预期的 class 和 companion object
提供 actual typealias
匹配 static
声明。关注本期更新:KT-29882.
目前,您可以通过在预期 Optional
class 之外单独声明工厂函数来解决此问题,如下所示:
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 上,您必须为 Optional
class 提供 actual typealias
,另外,为 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?
现在是一个错误:
Type alias expands to
T?
, which is not a class, an interface, or an object
所以你实际上需要一个非 JVM 实现。为避免为每个非 JVM 目标重复它,您可以声明一个自定义源集并 link 它与特定于平台的源集一起,以便他们从那里获得实现:
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