嵌套不同调度接收器的Compose代码块:抽象与类型问询
Kotlin多接收器Lambda抽象问题解答
前置代码
interface AProvider { fun getA(): String } interface BProvider { fun getB(): String } fun a(block: AProvider.() -> Unit) {} fun b(block: BProvider.() -> Unit) {}
原嵌套调用示例:
val x = a { b { getA(); getB() } }
构想的抽象方式:
val y = { l: ??? -> a { b(l) } } val z = y { getA(); getB() }
待解答问题
- 按上述
y的定义是否可行? - 若可行,参数
l的类型应是什么? - 若不可行,是否存在其他定义方式可让lambda访问多个调度接收器?
问题解答
不可行。
b函数要求传入的lambda类型是BProvider.() -> Unit,这个lambda的调度接收器只有BProvider,无法直接访问AProvider的getA()方法。而构想中直接把l传给b,l如果要调用getA(),必须同时拥有AProvider的上下文,但当前结构下无法让b的lambda同时持有两个调度接收器的上下文,所以这种定义方式走不通。由于第一种方式不可行,此问题无对应答案。
有三种可行方案实现lambda访问多个调度接收器:
方案一:合并接收器接口
定义一个同时继承AProvider和BProvider的接口,通过代理两个原接收器的方式让lambda能访问两者的方法:
interface ABProvider : AProvider, BProvider fun ab(block: ABProvider.() -> Unit) { a { b { // 创建代理类,同时代理AProvider和BProvider的实现 val abProxy = object : ABProvider { override fun getA() = this@a.getA() override fun getB() = this@b.getB() } abProxy.block() } } } // 使用示例 val z = ab { getA(); getB() }
方案二:显式传递外部接收器
让lambda接收外部的AProvider作为参数,同时保留BProvider作为自身的调度接收器:
val y = { l: AProvider.(BProvider) -> Unit -> a { b { // 将外部的AProvider和当前的BProvider传给lambda this@a.l(this) } } } // 使用示例:lambda中通过this@y访问AProvider,this访问BProvider val z = y { getA(); this.getB() }
方案三:利用Kotlin上下文接收器(1.6+)
Kotlin 1.6及以上支持上下文接收器特性,可以直接声明lambda需要同时拥有AProvider和BProvider两个上下文:
// 定义需要两个上下文的lambda类型 context(AProvider, BProvider) typealias ABBlock = () -> Unit val y = { l: ABBlock -> a { b { // 同时带入AProvider和BProvider的上下文执行lambda with(this@a) { l() } } } } // 使用示例:lambda自动拥有两个上下文,可直接调用两个方法 val z = y { getA(); getB() }
内容的提问来源于stack exchange,提问作者David Kubecka
相关产品推荐
相关产品推荐

