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

标签 initialization this lazy-evaluation kotlin

我试图将我的技巧从一个答案概括为另一个 question .

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

我现在拥有的:

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(h.x) //2

但是此时initializer引用构造值的方式是self属性。

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

还有哪些其他改进代码的方法?


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

最佳答案

我在仍然完全通用的同时设法制作的最好的是:

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
}

添加调用运算符让您可以通过以下方式使用它:

val h: Holder = selfReference { Holder(0) { this().x++ } }

这是我让它看起来像你“通常”写的最接近的东西。

遗憾的是,我认为不可能完全摆脱对元素的显式访问。因为要这样做,您需要一个 T.() -> T 类型的 lambda 参数,但是如果没有 T 的实例,您将无法调用该参数并且作为 T 一个泛型,没有干净安全的方法来获取这个实例。

但也许我错了,这可以帮助你想出解决问题的办法

关于initialization - 编写一个在初始化程序中提供自引用的 Kotlin util 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35100389/

相关文章:

c++ - "iterator cannot be defined in the current scope"错误

c++ - 在什么情况下,c++ 会将变量初始化为零?

javascript - 关于高阶函数回调中的 ‘this’ 的问题

javascript - 仍然对 JavaScript 中的 "this"关键字感到困惑

java - 并行无限 Java 流耗尽内存

R 惰性评估- 不工作

c# - 使用值编码 C# 的遗传算法初始种子多样性

c++ - 我可以使用 C++11 大括号初始化语法来避免为简单聚合声明琐碎的构造函数吗?

javascript - 为什么我们在此片段中使用 "this"关键字?

python - 在 Python 中协调 np.fromiter 和多维数组