是否可以在 Kotlin 中传递内联函数?
Is it possible to pass inline functions in Kotlin?
在使用 KotlinJs 为 JavaScript 编写代码时,我们通常需要小心处理 this
。
所以我们通常需要这个功能:
inline fun <T> thisAs() = js("this")
并在某处使用它:
this.click = {
thisAs<MyVueComponent.Data>().username = "changed"
}
由于VueJs的内在逻辑,我不得不生成JavaScript代码this.username
(this
是hardcode),但是很难看,我不想写thisAs<MyVueComponent.Data>().username
每次我需要一个 JavaScript this
.
所以我尝试通过定义函数 defineMethods
来改进它,如下所示:
external interface VueComponent<DATA, METHODS> {}
fun <DATA, METHODS> VueComponent<DATA, METHODS>.defineMethods(block: M.(() -> DATA) -> Unit): METHODS {
val methods = jsObj<M>()
block(methods, ::thisAs)
return methods
}
而且我希望内联函数 thisAs
仍然是一个内联函数,即使我将它作为 ::thisAs
传递给 block
,所以我可以这样重写代码:
this.methods = this.defineMethods { data ->
this.click = {
data().username += "changed!" // I want to write `data()` to generate a JavaScript `this`
}
}
但遗憾的是,函数 data
(即 ::thisAs
)不再内联,代码无法正常工作。
有什么办法可以解决吗?
更新:
- 添加一个完整的项目来演示这个问题,参见:https://github.com/kotlin-demos/kotlin-vue-demo/tree/js-this-issue。
我遇到了同样的问题。我有一个类似的函数来转换 Javascript 的 this 对象。但是,我用 lambda function with a receiver 扩展了它(与 Kotlin 中用于类型安全构建器的东西相同,除了我的函数 returns Unit 并且是内联)。
inline fun <T> withJsThis(body: T.() -> Unit) {
js("this").unsafeCast<T>().body()
}
它可以很容易地用于方法以及生命周期钩子(created、mounted,等等)。它需要一行额外的代码,但它很干净,并且在从 Kotlin 翻译成 Javascript 时完全产生预期的 this.variable。
class LoginComponent {
class Data {
var username: String = "test@test.com"
var password: String = ""
}
val data = {
Data()
}
val template = """<form>
<input type="text" v-model="username" placeholder="Email" /><br />
<input type="password" v-model="password" placeholder="Password" /><br />
<input type="submit" v-on:click.prevent="showInfo" />
</form>"""
val methods = object {
val showInfo: () -> Unit = {
withJsThis<Data> {
console.log("METHOD: USER = $username, PASS = $password")
}
}
}
fun mounted() {
withJsThis<Data> {
console.log("MOUNTED: USER = $username, PASS = $password")
}
}
}
在使用 KotlinJs 为 JavaScript 编写代码时,我们通常需要小心处理 this
。
所以我们通常需要这个功能:
inline fun <T> thisAs() = js("this")
并在某处使用它:
this.click = {
thisAs<MyVueComponent.Data>().username = "changed"
}
由于VueJs的内在逻辑,我不得不生成JavaScript代码this.username
(this
是hardcode),但是很难看,我不想写thisAs<MyVueComponent.Data>().username
每次我需要一个 JavaScript this
.
所以我尝试通过定义函数 defineMethods
来改进它,如下所示:
external interface VueComponent<DATA, METHODS> {}
fun <DATA, METHODS> VueComponent<DATA, METHODS>.defineMethods(block: M.(() -> DATA) -> Unit): METHODS {
val methods = jsObj<M>()
block(methods, ::thisAs)
return methods
}
而且我希望内联函数 thisAs
仍然是一个内联函数,即使我将它作为 ::thisAs
传递给 block
,所以我可以这样重写代码:
this.methods = this.defineMethods { data ->
this.click = {
data().username += "changed!" // I want to write `data()` to generate a JavaScript `this`
}
}
但遗憾的是,函数 data
(即 ::thisAs
)不再内联,代码无法正常工作。
有什么办法可以解决吗?
更新:
- 添加一个完整的项目来演示这个问题,参见:https://github.com/kotlin-demos/kotlin-vue-demo/tree/js-this-issue。
我遇到了同样的问题。我有一个类似的函数来转换 Javascript 的 this 对象。但是,我用 lambda function with a receiver 扩展了它(与 Kotlin 中用于类型安全构建器的东西相同,除了我的函数 returns Unit 并且是内联)。
inline fun <T> withJsThis(body: T.() -> Unit) {
js("this").unsafeCast<T>().body()
}
它可以很容易地用于方法以及生命周期钩子(created、mounted,等等)。它需要一行额外的代码,但它很干净,并且在从 Kotlin 翻译成 Javascript 时完全产生预期的 this.variable。
class LoginComponent {
class Data {
var username: String = "test@test.com"
var password: String = ""
}
val data = {
Data()
}
val template = """<form>
<input type="text" v-model="username" placeholder="Email" /><br />
<input type="password" v-model="password" placeholder="Password" /><br />
<input type="submit" v-on:click.prevent="showInfo" />
</form>"""
val methods = object {
val showInfo: () -> Unit = {
withJsThis<Data> {
console.log("METHOD: USER = $username, PASS = $password")
}
}
}
fun mounted() {
withJsThis<Data> {
console.log("MOUNTED: USER = $username, PASS = $password")
}
}
}