编写一个在初始化程序中提供自引用的Kotlin util函数

我试图从另一个问题的答案概括我的黑客。

它应该提供一种方法来引用一个尚未在其构造器中构造的值(当然,不是直接的,而是在lambda表达式和对象表达式中)。

我现在所拥有的:

class SelfReference<T>(val initializer: SelfReference<T>.() -> T) { val self: T by lazy { inner ?: throw IllegalStateException("Do not use `self` until initialized.") } private val inner = initializer() } fun <T> selfReference(initializer: SelfReference<T>.() -> T): T { return SelfReference(initializer).self } 

它的作品,看到这个例子:

 class Holder(var x: Int = 0, val action: () -> Unit) val h: Holder = selfReference { Holder(0) { self.x++ } } h.action() h.action() println(hx) //2 

但在这一点上, initializer引用构造值的方式是self属性。

而我的问题是:是否有一种方法来重写SelfReference以便initializer器传递一个参数(或接收器)而不是使用self属性? 这个问题可以重新表达为:是否有一种方法可以将延迟评估的接收器/参数传递给函数,或者以某种方式实现这种语义?

有什么其他的方法来改善代码?


UPD:一种可能的方式是传递一个返回self的函数,因此它将在initializer用作it() 。 还在寻找其他的。

有没有一种方法来重写SelfReference,以便初始化器传递一个参数(或接收器)而不是使用自己的属性? 这个问题可以重新表达为:是否有一种方法可以将延迟评估的接收器/参数传递给函数,或者以某种方式实现这种语义?

我不确定我完全理解你的用例,但这可能是你正在寻找的:

 fun initHolder(x: Int = 0, holderAction: Holder.() -> Unit) : Holder { var h: Holder? = null h = Holder(x) { h!!.holderAction() } return h } val h: Holder = initHolder(0) { x++ } h.action() h.action() println(hx) // 2 

这是holderAction因为holderAction是一个带有接收方( Holder.() -> Unit )的lambda,给予接收方成员lambda的访问权限。

这是一个通用的解决方案,因为您可能无法更改各个Holder构造函数的签名。 值得注意的是,这个解决方案不需要类是开放的,否则类似的方法可以通过使用次级构造函数的子类来完成。

当只有少数需要更改的类时,我更喜欢使用此解决方案来创建SelfReference类。

你可能要检查null而不是使用!! 为了抛出一个有用的错误。 如果Holder在构造函数或init块中调用action ,你将会得到一个空指针异常。