Cómo realizar la initialization en varios pasos de val

Para aprender un poco de kotlin , estoy construyendo una biblioteca de combinador de analizadores basada libremente en el clásico papel Monadic Parser Combinators .

En mi caso, necesito reenviar declarar un analizador debido a la syntax recursiva. Al preparar el analizador de expresiones finales, necesito actualizar la statement directa

Mi primer bash fue esto

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

La idea es realizar una initialization corta y luego devolver addLike para inicializar el valor. Este es un patrón muy común cuando realizo algunos progtwigs F # y creo que es un buen patrón porque simplifica el ocultamiento de los detalles de initialization.

Esto no funciona en kotlin sin embargo:

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

Este enfoque también falla:

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

El problema parece ser eso ; combina dos expressions en una statement .

Así que lo intenté , con la esperanza de que se comportara algo así como C / C ++, pero sin suerte:

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

Después de leer la especificación de kotlin no encontré soluciones claras, por eso recurrí a StackOverflow. ¿Se puede implementar este patrón de manera idiomática en kotlin ?

Actualizar

@Eric sugirió el uso si se run y si actualizo mi código con eso, la solución final termina así:

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

Que es aceptable para mi Gracias @Eric.

Hay muchas forms de ejecutar código de initialization en un object antes de asignarlo a cualquier campo de datos.

Puede usar la function de run . con run puede escribir una function lambda donde puede realizar su código de initialization y luego asignar el valor devuelto de lambda como el valor del campo de datos:

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

también puedes usar apply como se menciona en la respuesta de Alexander Udalov . Puede crear una instancia del valor al que le gustaría asignar el campo de datos y hacer que se apply el código de initialization en el lambda pasado:

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

puedes usar el delegado perezoso . esto es similar a ejecutar, excepto que el lambda no se ejecutará de inmediato durante la construcción para inicializar el campo de datos. en su lugar, se ejecutará la primera vez que se acceda al campo de datos:

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

Puede usar la function apply de la biblioteca estándar. Realiza una operación en su receptor y luego lo devuelve:

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