Как выполнить многоступенчатую инициализацию val

Чтобы немного узнать о 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.

Существует много способов выполнить код инициализации объекта перед его назначением в любое поле данных.

Вы можете использовать функцию run . с run вы можете написать функцию лямбда, где вы можете выполнить свой код инициализации, а затем назначить возвращаемое значение лямбда в качестве значения поля данных:

 val expression = run() { // initialization code here forwarded.second(addLike) // writing "return@run" is optional return@run addLike } 

вы также можете использовать apply как указано в ответе Александра Удалова . вы можете создать экземпляр значения, которому вы хотите присвоить поле данных, и ввести код инициализации в лямбда, который был принят:

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

вы можете использовать ленивого делегата . это похоже на запуск, за исключением того, что лямбда не будет выполняться сразу во время построения, чтобы инициализировать поле данных. вместо этого он будет выполняться при первом обращении к полю данных:

 val expression by lazy() { // initialization code here forwarded.second(addLike) // writing "return@run" is optional return@lazy addLike } 

Вы можете использовать функцию apply из стандартной библиотеки. Он выполняет операцию на своем приемнике, а затем возвращает его:

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