编写一个在初始化程序中提供自引用的 Kotlin util 函数 [英] Writing a Kotlin util function which provides self-reference in initializer

查看:16
本文介绍了编写一个在初始化程序中提供自引用的 Kotlin util 函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将我的技巧从另一个问题的答案中概括出来.

I'm trying to generalize my hack from an answer to another question.

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

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
}

它有效,看这个例子:

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
}

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

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.() -> 类型的 lambda 参数.T 但是如果没有 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 Tand 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆