如何执行val的多步骤初始化

时间:2016-06-24 08:07:46

标签: kotlin

为了学习一点kotlin我正在基于经典论文Monadic Parser Combinators 松散地构建一个解析器组合库。

在我的情况下,由于递归语法,我需要转发声明一个解析器。在准备最终表达式解析器时,我需要更新前向声明

我的第一次尝试就是这个

val addLike             = mulLike separatedBy addLikeSeparator
val expression          = 
  forwarded.second(addLike)
  addLike

想法是执行简短的初始化,然后返回addLike来初始化值。当我进行一些F#编程时,这是一种非常常见的模式,我认为它是一个很好的模式,因为它简化了隐藏初始化细节。

但这并不适用于kotlin

Error:(195, 5) Kotlin: Expecting a top level declaration

这种方法也失败了:

val addLike             = mulLike separatedBy addLikeSeparator
val expression          = forwarded.second(addLike); addLike

问题似乎是;将两个expressions合并为一个statement

所以我尝试了,,希望它的行为有点像C / C ++,但没有运气:

val addLike             = mulLike separatedBy addLikeSeparator
val expression          = forwarded.second(addLike), addLike

在阅读kotlin规范后,我发现没有明确的解决方案,这就是我转向StackOverflow的原因。这种模式可以在kotlin中以惯用的方式实现吗?

更新

@Eric建议使用if run,如果我用我的代码更新代码,最终的解决方案有点像这样:

val expression          = run () {
                                forwarded.second(addLike)
                                whitespaces keepRight addLike keepLeft expectEOS()
                          }

我可以接受。谢谢@Eric。

2 个答案:

答案 0 :(得分:8)

您可以使用标准库中的apply功能。它在接收器上执行操作然后返回它:

val expression = addLike.apply { forwarded.second(this) }

答案 1 :(得分:3)

在将对象分配给任何数据字段之前,有很多方法可以在对象上执行初始化代码。

您可以使用run功能。使用run,您可以编写一个lambda函数,您可以在其中执行初始化代码,然后将lambda的返回值指定为数据字段的值:

val expression = run()
{
    // initialization code here
    forwarded.second(addLike)

    // writing "return@run" is optional
    return@run addLike
}

您还可以使用apply中提到的Alexander Udalov's answer。你可以实例化你想要分配数据字段的值,并将lambda中的初始化代码传递给apply

val variable = addLike.apply()
{
    // initialization code here
    forwarded.second(this) // "this" refers to addLike within this lambda
}

您可以使用lazy delegate。这与run类似,只是lambda在构造期间不会立即执行以初始化数据字段。相反,它将在第一次访问数据字段时执行:

val expression by lazy()
{
    // initialization code here
    forwarded.second(addLike)

    // writing "return@run" is optional
    return@lazy addLike
}