Kotlin多平台对Optional的支持

时间:2019-11-23 10:39:06

标签: kotlin kotlin-multiplatform

我正在使用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类?
  • 有没有一种方法可以避免在非Java目标上重新实现 fake 可选类(即,习惯使用nullable ?后缀的情况)

1 个答案:

答案 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