¿Cuál es la diferencia entre las palabras clave "const" y "final" en Dart?

172

¿Cuál es la diferencia entre consty finalpalabra clave en Dart?

Ishmal Ijaz
fuente
1
Aquí hay algunos detalles sobre const: stackoverflow.com/questions/51576209/… y la simple explotación a finales constante (no se puede reasignar o asignar una vez creada con la palabra clave final) y debe inicializarla una vez.
Blasanka

Respuestas:

236

Hay una publicación en el sitio web de Dart y lo explica bastante bien.

Final:

"final" significa asignación única: una variable o campo final debe tener un inicializador. Una vez asignado un valor, el valor de una variable final no se puede cambiar. final modifica las variables .


Const:

"const" tiene un significado que es un poco más complejo y sutil en Dart. const modifica los valores . Puede usarlo al crear colecciones, como const [1, 2, 3], y al construir objetos (en lugar de nuevos) como const Point (2, 3). Aquí, const significa que todo el estado profundo del objeto se puede determinar completamente en tiempo de compilación y que el objeto estará congelado y completamente inmutable.

Los objetos Const tienen un par de propiedades y restricciones interesantes:

Deben crearse a partir de datos que puedan calcularse en tiempo de compilación. Un objeto const no tiene acceso a nada que deba calcular en tiempo de ejecución. 1 + 2 es una expresión constante válida, pero la nueva DateTime.now () no lo es.

Son profunda, transitivamente inmutables. Si tiene un campo final que contiene una colección, esa colección aún puede ser mutable. Si tiene una colección constante, todo lo que contiene también debe ser constante, recursivamente.

Están canonicalizados . Esto es algo así como una cadena interna: para cualquier valor const dado, se creará un objeto const único y se reutilizará sin importar cuántas veces se evalúen las expresiones const.


¿Entonces, qué significa esto?

Const:
Si el valor que tiene se calcula en tiempo de ejecución ( new DateTime.now()por ejemplo), puede no utilizar una constante para él. Sin embargo, si el valor se conoce en el momento de la compilación ( const a = 1;), debe usar constmás definal . Hay otras 2 grandes diferencias entre consty final. En primer lugar, si está usando const, debe declararlo en static constlugar de solo const. En segundo lugar, si tienes una constcolección, todo lo que está dentro está dentro const. Si tiene una finalcolección, todo lo que contiene no lo es final.

Final:
final debe usarse constsi no conoce el valor en tiempo de compilación, y se calculará / tomará en tiempo de ejecución. Si desea una respuesta HTTP que no se puede cambiar, si desea obtener algo de una base de datos o si desea leer desde un archivo local, use final. Cualquier cosa que no se conozca en tiempo de compilación debería haber finalterminado const.


Dicho todo esto, ambos consty finalno se pueden reasignar, pero los campos en un finalobjeto, siempre que no lo sean consto finalse pueden reasignar (a diferencia const).

meyi
fuente
3
La palabra clave const se usa para representar una constante de tiempo de compilación. Las variables declaradas usando la palabra clave const son implícitamente finales.
Arun George
1
@Meyi, ¿cuándo debemos usar consty cuándo final? ¿Conoces algún tipo de caso de uso para estos modificadores?
CopsOnRoad
44
@CopsOnRoad puedes ver este video Dart Const vs Final
Lemuel Ogbunude
2
Esa última oración realmente lo resume muy bien. Gracias por eso.
Yster
¿Deberíamos preocuparnos de que la constante sea una opción? ¿La ganancia de rendimiento es realmente perceptible?
CodeGrue
63

Const

El valor debe conocerse en tiempo de compilación . const birthday = "2008/12/26"
No se puede cambiar después de inicializado.


Final

El valor debe conocerse en tiempo de ejecución . final birthday = getBirthDateFromDB()
No se puede cambiar después de inicializado.

Haroun Hajem
fuente
10
La explicación más fácil y mejor.
Ankur Lahiry
1
Me encantó este :)
Faisal Naseer
43

Consolidado @Meyi y @ faisal-naseer respuestas y comparación con poca programación.

const:

La palabra clave const se usa para hacer que una variable almacene un valor constante de tiempo de compilación . El valor constante de tiempo de compilación es un valor que será constante durante la compilación :-)

Por ejemplo, 5es una constante de tiempo de compilación. Mientras DateTime.now()que no es tiempo de compilación constante. Porque este método devolverá el tiempo cuando la línea se ejecuta en tiempo de ejecución. Entonces no podemos asignar el DateTime.now()a una constvariable.

const a = 5;
// Uncommenting below statement will cause compile time error.
// Because we can't able to assign a runtime value to a const variable
// const b = DateTime.now();

Debe inicializarse en la misma línea .

const a = 5;
// Uncommenting below 2 statement will cause compilation error.
// Because const variable must be initialized at the same line.
// const b;
// b = 6;

Todas las declaraciones mencionadas a continuación son aceptables.

// Without type or var
const a = 5;
// With a type
const int b = 5;
// With var
const var c = 6;

La variable const de nivel de clase debe inicializarse como a continuación.

Class A {
    static const a = 5;
}

La variable const de nivel de instancia no es posible .

Class A {
    // Uncommenting below statement will give compilation error.
    // Because const is not possible to be used with instance level 
    // variable.
    // const a = 5;
}

El otro uso importante de constse usa para hacer que el objeto sea inmutable . Para hacer que un objeto de clase sea inmutable, necesitamos usar la palabra clave const con constructor y hacer que todos los campos sean finales como se menciona a continuación.

Class A {
    final a, b;
    const A(this.a, this.b);
}

void main () {
    // There is no way to change a field of object once it's 
    // initialized.
    const immutableObja = const A(5, 6);
    // Uncommenting below statement will give compilation error.
    // Because you are trying to reinitialize a const variable
    // with other value
    // immutableObja = const A(7, 9);

    // But the below one is not the same. Because we are mentioning objA 
    // is a variable of a class A. Not const. So we can able to assign
    // another object of class A to objA.
    A objA = const A(8, 9);
    // Below statement is acceptable.
    objA = const A(10, 11);
}

podemos usar la palabra clave const para una lista .

const a = const [] - Una variable a inicializada constque contiene una lista de constobjetos (es decir, la lista debe contener solo objetos constantes de tiempo de compilación e inmutables). Entonces no podemos asignar acon otra lista .

var a = const [] - Una variable a inicializada como varque contiene una lista de constobjetos . Entonces podemos asignar otra lista a la variablea .

Class A {
    final a, b;
    const A(this.a, this.b);
}

class B {
    B(){ // Doing something }
}

void main() {
    const constantListOfInt = const [5, 6, 7,
                 // Uncommenting below statement give compilation error.
                 // Because we are trying to add a runtime value
                 // to a constant list
                 // DateTime.now().millisecondsSinceEpoch
              ];
    const constantListOfConstantObjA = const [
        A(5, 6),
        A(55, 88),
        A(100, 9),
    ];
    // Uncommenting below 2 statements will give compilation error.
    // Because we are trying to reinitialize with a new list.
    // constantListOfInt = [8, 9, 10];
    // constantListOfConstantObjA = const[A(55, 77)];

    // But the following lines are little different. Because we are just
    // trying to assign a list of constant values to a variable. Which 
    // is acceptable
    var variableWithConstantList = const [5, 6, 7];
    variableWithConstantList = const [10, 11, 15];
    var variableOfConstantListOfObjA = const [A(5, 8), A(7, 9), A(10, 4)];
    variableWithConstantList = const [A(9, 10)];
}

final:

La palabra clave final también se usa para hacer que la variable mantenga un valor constante . Una vez inicializado, no podemos cambiar el valor.

final a = 5;
// Uncommenting below statement will give compilation error.
// Because a is declared as final.
// a = 6;

Todas las declaraciones mencionadas a continuación son aceptables.

// Without type or var
final a = 5;
// With a type
final int b = 5;
// With var
final var c = 6;

Puede asignar un valor de tiempo de ejecución .

// DateTime.now() will return the time when the line is getting
// executed. Which is a runtime value.
final a = DateTime.now();
var b = 5;
final c = b;

La variable final de nivel de clase debe inicializarse en la misma línea.

Class A {
    static final a = 5;
    static final b = DateTime.now();
}

La variable final de nivel de instancia debe inicializarse en la misma línea o en la inicialización del constructor. El valor se guardará en la memoria cuando se cree el objeto.

Class A {
    final a = 5;
}

// Constructor with a parameter.
Class B {
    final b;
    B(this.b);
}

// Constructor with multiple parameter.
Class C {
    final c;
    C(this.c, int d) {
        // Do something with d
    }
}

void main() {
    A objA = new A();
    B objB = new B(5);
    C objC = new C(5, 6);
}

Asignación de una lista .

final a = [5, 6, 7, 5.6, A()];
// Uncommenting Below statement will give compilation error.
// Because we are trying to reinitialize the object with another list.
// a = [9.9, 10, B()];
Mahendran Sakkarai
fuente
20

Extendiendo la respuesta por @Meyi

  • La variable final solo se puede configurar una vez y se inicializa cuando se accede a ella (por ejemplo, en la sección de código a continuación si usa el valor de biggestNumberOndicesolo entonces el valor se inicializará y se asignará memoria).
  • const es internamente de naturaleza final, pero la principal diferencia es que su constante de tiempo de compilación, que se inicializa durante la compilación, incluso si no usa su valor, se inicializará y ocupará espacio en la memoria.

  • La variable de las clases puede ser final pero no constante y si desea una constante a nivel de clase, haga que sea constante.

Código:

void main() {

    // final demonstration
    final biggestNumberOndice = '6';
    //  biggestNumberOndice = '8';     // Throws an error for reinitialization

    // const
    const smallestNumberOnDice = 1;

}

class TestClass {

    final biggestNumberOndice = '6';

    //const smallestNumberOnDice = 1;  //Throws an error
    //Error .  only static fields can be declared as constants.

    static const smallestNumberOnDice = 1;
}
Faisal Naseer
fuente
2
Creo que una mejor manera de hacer la pregunta es cuándo preferir la inicialización en tiempo de ejecución sobre la inicialización en tiempo de compilación ...
Faisal Naseer
y para eso puedes consultar la respuesta de @Meyi y también visitar el enlace del artículo de su publicación, es maravilloso :)
Faisal Naseer
2

Ambos finaly constevitan que se reasigne una variable (similar a cómo finalfunciona en Java o cómoconst funciona en JavaScript).

La diferencia tiene que ver con cómo se asigna la memoria. La memoria se asigna para una finalvariable en tiempo de ejecución y para una constvariable en tiempo de compilación. El finalmodificador debería ser el más utilizado, porque muchas variables de programa no necesitarán memoria ya que la lógica del programa no requerirá que se inicialicen. Con unconst variable, básicamente le está diciendo a la computadora: "Oye, necesito memoria para esta variable por adelantado porque sé que la voy a necesitar".

Pensar en ellos de esta manera hace que sea más fácil comprender las diferencias en su uso sintáctico. Principalmente que unfinal variable puede ser una variable de instancia, pero a constdebe ser una staticvariable en una clase. Esto se debe a que las variables de instancia se crean en tiempo de ejecución y las constvariables, por definición, no. Por lo tanto, las constvariables en una clase deben ser static, lo que significa simplemente que existe una sola copia de esa variable en una clase, independientemente de si esa clase está instanciada.

Este video lo desglosa de manera bastante simple: https://www.youtube.com/watch?v=9ZZL3iyf4Vk

Este artículo profundiza y explica una diferencia semántica muy importante entre los dos, es decir, finalmodifica las variables y constmodifica los valores, que esencialmente se reduce a solo poder inicializar constvalores que son derivables en tiempo de compilación.

https://news.dartlang.org/2012/06/const-static-final-oh-my.html

holding_the_center_down
fuente
2

final y const en dardo son confusos al nivel que creemos que ambos son iguales.

Veamos sus diferencias:

PD: incluí la imagen en lugar del texto, ya que no pude tabular la información en formato Stackoverflow .md fácilmente.

erluxman
fuente
1

Si vienes desde C++entonces constadentro Dartestá constexpradentro C++y finaladentro Dartestá constadentro C++.

Lo anterior se aplica solo a los tipos primitivos. Sin embargo, en los Dartobjetos marcados finalson mutables en términos de sus miembros.

Moshe Rabaev
fuente
2
Algo así como. Creo que se podría decir esto para los tipos primitivos pero no para los objetos. consten C ++ casi siempre se usa para especificar que un objeto no es mutable a través de una referencia o puntero específico. finalin Dart no evita que el objeto sea mutado a través de esa variable.
jamesdlin
0

No puedes inicializar a constusando a final. Por ejemplo :

  final myConst = 1;
  const myFinal = 2;

  final a = myConst; // possible
  final b = myFinal; // possible
  const c = myConst; // this is not possible
  const d = myFinal; // possible
Jéwôm '
fuente
0

¿Cuándo usar qué palabra clave?

Un ejemplo simple para ambos: Use final: si no sabe cuál será su valor en tiempo de compilación. Por ejemplo, cuando puede necesitar obtener datos de una API, esto sucede cuando ejecuta su código.

Use const: si está seguro de que no se cambiará un valor al ejecutar su código. Por ejemplo, cuando declaras una oración que siempre permanece igual.

https://itnext.io/difference-between-const-and-final-in-dart-78c129d0c573

Faisal Ahmed
fuente