You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何扩展Kotlin的with函数使其支持多参数调用?

Extending Kotlin's with for Multiple Parameters

Great question! Kotlin's with function is such a clean way to scope operations to a single object, so wanting to extend that pattern to handle multiple targets is totally reasonable. Unfortunately, the native with uses a single-receiver lambda, which means it can't natively expose multiple objects as the implicit this in the block. But we can absolutely build our own version to support multi-parameter use cases—let's break down a few practical options.

Option 1: Dual-Parameter with with Receiver + Argument

This approach keeps the familiar scoping feel, using the first object as the lambda's receiver (this) and passing the second as an explicit argument (you can name it for clarity instead of relying on it):

fun <T1, T2, R> with(first: T1, second: T2, block: T1.(T2) -> R): R {
    return first.block(second)
}

Usage Example:

data class Foo(val name: String) {
    fun fooFunction() = println("Foo says: $name")
}

data class Bar(val id: Int) {
    fun barFunction() = println("Bar's ID: $id")
}

fun main() {
    val foo = Foo("Kotlin")
    val bar = Bar(42)
    
    with(foo, bar) { barObj ->
        fooFunction() // Implicitly uses `this` (foo)
        barObj.barFunction() // Explicit reference to bar
    }
}

Option 2: Multi-Parameter Lambda with Explicit Arguments

If you prefer full clarity over implicit receivers, this version passes both objects as named parameters to the lambda. It's straightforward and avoids any ambiguity:

fun <T1, T2, R> with(first: T1, second: T2, block: (T1, T2) -> R): R {
    return block(first, second)
}

Usage Example:

with(foo, bar) { fooObj, barObj ->
    fooObj.fooFunction()
    barObj.barFunction()
}

You can also use destructuring with a Pair if you want to stick closer to the native with signature:

with(foo to bar) { (fooObj, barObj) ->
    fooObj.fooFunction()
    barObj.barFunction()
}

Option 3: Combined Context Class (For Advanced Use Cases)

If you frequently need to access members of both objects without prefixes, you could create a wrapper class that delegates properties and methods to both targets. This requires a bit more setup but gives you a clean, prefix-free experience:

class FooBarContext(val foo: Foo, val bar: Bar) {
    // Delegate Foo's members
    fun fooFunction() = foo.fooFunction()
    val fooName get() = foo.name
    
    // Delegate Bar's members
    fun barFunction() = bar.barFunction()
    val barId get() = bar.id
}

fun <R> with(foo: Foo, bar: Bar, block: FooBarContext.() -> R): R {
    return FooBarContext(foo, bar).block()
}

Usage Example:

with(foo, bar) {
    fooFunction() // No prefix needed!
    barFunction()
    println("Foo: $fooName, Bar: $barId")
}

Quick Note on Idioms

The native with's simplicity comes from its single-receiver design. For multiple objects, explicit references (or a wrapper context) are the most idiomatic Kotlin approaches—they avoid confusion and keep your code readable for other developers.

内容的提问来源于stack exchange,提问作者svkaka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:48:02