¿Por qué la variable no se puede inicializar correctamente en la function en línea como en Java?

Sabemos que el cuerpo lambda está perezosamente bien, porque si no llamamos a la lambda nunca se llamará al código en el cuerpo lambda.

También sabemos en cualquier lenguaje de function que una variable puede usarse en una function / lambda incluso si no está inicializada, como javascript, ruby, groovy y .etc, por ejemplo, el siguiente código groovy puede funcionar bien:

def foo def lambda = { foo } foo = "bar" println(lambda()) // ^--- return "bar" 

También sabemos que podemos acceder a una variable no inicializada si el bloque catch ha inicializado la variable cuando se genera una exception en try-block en Java, por ejemplo:

 // v--- m is not initialized yet int m; try{ throw new RuntimeException(); } catch(Exception ex){ m = 2;} System.out.println(m);// println 2 

Si la lambda es perezosa, ¿por qué Kotlin no puede usar una variable no inicializada en lambda? Sé que Kotlin es un lenguaje de security nula, por lo que el comstackdor analizará el código de arriba a abajo para include el cuerpo lambda y asegurarse de que la variable esté inicializada. por lo que el cuerpo lambda no es "perezoso" en time de compilation. por ejemplo:

 var a:Int val lambda = { a }// lambda is never be invoked // ^--- a compile error thrown: variable is not initialized yet a = 2 

P : ¿Pero por qué el código a continuación tampoco puede funcionar? No lo entiendo, dado que la variable es efectivamente definitiva en Java, si desea cambiar el valor de la variable debe usar un ObjectRef en ObjectRef lugar, y esta testing contradice mis conclusiones anteriores: "el cuerpo lambda no está perezosamente en time de compilation " .por ejemplo:

 var a:Int run{ a = 2 }// a is initialized & inlined to callsite function // v--- a compile error thrown: variable is not initialized yet println(a) 

Así que lo único que puedo pensar es que el comstackdor no puede asegurar que el campo de element en ObjectRef esté inicializado o no, pero @hotkey ha negado mis pensamientos. Por qué ?

P : ¿por qué las funciones en línea de Kotlin no pueden funcionar bien incluso si estoy inicializando la variable en catch-block como en java? por ejemplo:

 var a: Int try { run { a = 2 } } catch(ex: Throwable) { a = 3 } // v--- Error: `a` is not initialized println(a) 

Pero, @hotkey ya ha mencionado que debes usar la expresión try-catch en Kotlin para inicializar una variable en su respuesta , por ejemplo:

 var a: Int = try { run { 2 } } catch(ex: Throwable) { 3 } // v--- println 2 println(a); 

P : Si realmente es eso, ¿por qué no llamo directamente a la run ? por ejemplo:

 val a = run{2}; println(a);//println 2 

Sin embargo, el código anterior puede funcionar bien en Java, por ejemplo:

 int a; try { a = 2; } catch (Throwable ex) { a = 3; } System.out.println(a); // println 2 

    P: ¿Pero por qué el código a continuación tampoco puede funcionar?

    Porque el código puede cambiar En el punto donde se define el lambda, la variable no se inicializa, por lo que si se cambia el código y se invoca el lambda directamente después, no sería válido. El comstackdor de kotlin quiere asegurarse de que no hay absolutamente ninguna manera de acceder a la variable no inicializada antes de que se inicialice, incluso por proxy.

    P: ¿por qué las funciones en línea de Kotlin no pueden funcionar bien incluso si estoy inicializando la variable en catch-block como en java?

    Porque run no es especial y el comstackdor no puede saber cuándo se ejecuta el cuerpo. Si considera que no se ejecuta la ejecución, el comstackdor no puede garantizar que la variable se inicialice.

    En el ejemplo modificado, utiliza la expresión try-catch para ejecutar esencialmente a = run { 2 } , que es diferente de run { a = 2 } porque el resultado está garantizado por el tipo de devolución.

    P: Si realmente es eso, ¿por qué no invoco la ejecución directamente?

    Eso es esencialmente lo que sucede. En cuanto al último código de Java, el hecho es que Java no sigue exactamente las mismas reglas de Kotlin y lo mismo ocurre al revés. El hecho de que algo sea posible en Java no significa que sea válido Kotlin.

    Puedes hacer que la variable sea floja con lo siguiente …

     val a: Int by lazy { 3 } 

    Obviamente, podría usar una function en lugar del 3. Pero esto permite que el comstackdor continúe y garantiza que a se inicialice antes de su uso.

    Editar

    Aunque la pregunta parece ser "¿por qué no se puede hacer?". Estoy en el mismo marco mental, que no veo por qué no (dentro de lo razonable). Creo que el comstackdor tiene suficiente información para descubrir que una statement lambda no es una reference a ninguna de las variables de cierre. Por lo tanto, creo que podría mostrar un error diferente cuando se utiliza el lambda y las variables a las que hace reference no se han inicializado.

    Dicho esto, esto es lo que haría si los networkingactores del comstackdor no estuvieran de acuerdo con mi evaluación (o tarden demasiado en llegar a la function).

    El siguiente ejemplo muestra una forma de hacer una initialization de variable local perezosa (para la versión 1.1 y posterior)

     import kotlin.reflect.* //... var a:Int by object { private var backing : Int? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = backing ?: throw Exception("variable has not been initialized") operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { backing = value } } var lambda = { a } // ... a = 3 println("a = ${lambda()}") 

    Usé un object anónimo para mostrar las agallas de lo que está sucediendo (y porque la lazy provocó un error de compilation). El object podría convertirse en function como lazy .

    Ahora estamos potencialmente volviendo a una exception de time de ejecución si el progtwigdor olvida inicializar la variable antes de que se haga reference a ella. Pero Kotlin intentó al less ayudarnos a evitar eso.