为了学习一点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。
答案 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
}