Scala LanguageVar, Val y Def


Observaciones

Como los val son semánticamente estáticos, se inicializan "en el lugar" donde aparecen en el código. Esto puede producir un comportamiento sorprendente e indeseable cuando se usa en clases abstractas y rasgos.

Por ejemplo, digamos que nos gustaría hacer un rasgo llamado PlusOne que defina una operación de incremento en un Int envuelto. Dado que los Int s son inmutables, el valor más uno se conoce en la inicialización y nunca se cambiará después, por lo que semánticamente es un valor val . Sin embargo, definirlo de esta manera producirá un resultado inesperado.

trait PlusOne {
    val i:Int

    val incr = i + 1
}

class IntWrapper(val i: Int) extends PlusOne

No importa cuál es el valor i se construye IntWrapper con, llamando .incr en el objeto devuelto siempre devuelve 1. Esto es porque el val incr es inicializado en el rasgo, antes de la clase que se extiende, y en ese momento i sólo tiene el valor por defecto de 0 . (En otras condiciones, puede completarse con Nil , null o un valor predeterminado similar).

La regla general, entonces, es evitar usar val en cualquier valor que dependa de un campo abstracto. En su lugar, use lazy val , que no evalúa hasta que se necesita, o def , que evalúa cada vez que se llama. Sin embargo, tenga en cuenta que si el valor de lazy val es forzado a evaluar por un val antes de que se complete la inicialización, ocurrirá el mismo error.

Un violín (escrito en Scala-Js, pero se aplica el mismo comportamiento) se puede encontrar aquí.

Var, Val y Def Ejemplos relacionados