编写Kotlin util函数,该函数在初始化程序中提供自引用 [英] Writing a Kotlin util function which provides self-reference in initializer
问题描述
我正试图通过回答另一个问题来概括我的黑客行为.
I'm trying to generalize my hack from an answer to another question.
它应该提供一种方法来引用尚未在其初始化程序内部构造的值(当然,不是直接构造,而是在lambda和对象表达式中).
It should provide a way to reference a value which is not constructed yet inside its initializer (of course, not directly, but in lambdas and object expressions).
我现在有什么:
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
}
它有效,请参见以下示例:
It works, see this example:
class Holder(var x: Int = 0,
val action: () -> Unit)
val h: Holder = selfReference { Holder(0) { self.x++ } }
h.action()
h.action()
println(h.x) //2
但是在这一点上,initializer
引用构造值的方式是self
属性.
But at this point the way in which initializer
references the constructed value is self
property.
我的问题是:有没有办法重写SelfReference
,以便将initializer
传递给参数(或接收者)而不是使用self
属性?这个问题可以重新表述为:是否有一种方法可以将惰性计算的接收器/参数传递给函数或以某种方式实现此语义?
And my question is: is there a way to rewrite SelfReference
so that initializer
is passed an argument (or a receiver) instead of using self
property? This question can be reformulated to: is there a way to pass a lazily evaluated receiver/argument to a function or achieve this semantics some way?
还有什么其他方法可以改善代码?
UPD:一种可能的方法是传递一个返回
self
的函数,因此该函数将在initializer
中用作it()
.还在寻找其他人.
What are the other ways to improve the code?
UPD: One possible way is to pass a function that returns
self
, thus it would be used as it()
inside the initializer
. Still looking for other ones.
推荐答案
在完全通用的情况下,我设法做到的最好是:
The best I have managed to produce while still being completely generic is this:
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()
operator fun invoke(): T = self
}
添加invoke操作符后,您可以通过以下方式使用它:
Adding the invoke operator lets you use it in the following way:
val h: Holder = selfReference { Holder(0) { this().x++ } }
这是我使它看起来像您正常"编写的内容最接近的东西.
This is the closest I got to make it look like something you would "normally" write.
可悲的是,我认为不可能完全摆脱对该元素的显式访问.既然这样做,您将需要一个类型为T.() -> T
的lambda参数,但是如果没有T
实例并且您是T的泛型,您将无法调用该参数,因此没有干净,安全的方法来获取该实例
Sadly I think it is not possible to get completely rid of a explicit access to the element. Since to do that you would need a lambda parameter of type T.() -> T
but then you wouldn't be able to call that parameter without an instance of T
and being T a generic there is no clean and safe way to acquire this instance.
但是也许我错了,这可以帮助您考虑解决问题的方法
But maybe I'm wrong and this helps you think of a solution to the problem
这篇关于编写Kotlin util函数,该函数在初始化程序中提供自引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!