编写一个在初始化程序中提供自引用的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
,你将会得到一个空指针异常。