1

背景:JavaScript 中的选项对象

JavaScript 中的一个常见概念是这样的:

function MyLibrary(options) {
    if (options.optionA) { /* ... */ }
    if (options.optionB) { /* ... */ }
    if (options.flagC) { /* ... */ }
}

new MyLibrary({optionA: "foo", flagC: true})

所以基本上我们有一个“选项”对象,其中包含许多可选的属性。

问题:如何与 Kotlin 进行交互?

在 Kotlin 中,我们可能更愿意使用具有默认值的命名参数。但是,我想与使用上述概念的现有 JavaScript 库进行交互。我如何描述和使用 Kotlin 中的那个库?当然,它应该尽可能类型安全。

到目前为止我尝试过的

这是我想出的:

interface Options {
    var optionA: String
    var optionB: Int
    var flagC: Boolean
}

external class MyLibrary(options: Options)

fun myFunWithApply() {
    MyLibrary(Any().unsafeCast<Options>().apply {
        optionA = "foo"
        flagC = true
    })
}

这确实有效,它还为选项提供了代码完成,这很棒,虽然它不像原始 JavaScript 那样短,但考虑到它的长度,感觉还可以。但是...有更好的方法吗?没有 有没有办法相处unsafeCast

4

2 回答 2

0

有没有办法在没有 unsafeCast 的情况下相处?

是的,当然。

private external interface IOptions {
    val optionA: String
    val optionB: Int
    val flagC: Boolean
}

class Options(
    override val optionA: String,
    override val optionB: Int,
    override val flagC: Boolean
) : IOptions

external class MyLibrary(options: Options)

用法:

fun foo() {
    MyLibrary(Options(
        optionA = "foo",
        flagC = true
    ))
}

IOptions需要外部接口来防止Options成员名称被破坏。该类Options本身不能是外部的,因为 JS 中没有定义这样的类/构造函数。

需要注意的是,生成的 JS 代码效率会稍低——将有一个完整的附加类 ( Options) 和一个将参数分配给属性的构造函数调用,而不仅仅是一个 JS 对象字面量。但是,一旦涉及的代码被 jitter 处理,它可能就没有什么区别了。

于 2021-11-10T22:15:44.383 回答
0

但是...有更好的方法吗?有没有办法在没有 unsafeCast 的情况下相处?

您可能要考虑继续使用unsafeCast,但隐藏它。

external interface Options {
    var optionA: String
    var optionB: Int
    var flagC: Boolean
}

external class MyLibrary(options: Options)

@OptIn(ExperimentalContracts::class)
inline fun Options(
    block: Options.() -> Unit
): Options {
    
    contract {
        callsInPlace(block, kind = InvocationKind.EXACTLY_ONCE)
    }
    
    return Any().unsafeCast<Options>().apply(block)
}

用法:

fun myFunWithApply() {
    MyLibrary(Options {
        optionA = "foo"
        flagC = true
    })
}

与我的其他答案相比,这应该转化为更高效的 JS 代码。无论如何,这通常并不重要。

于 2021-11-10T22:21:31.747 回答