在Dart中,const和final关键字之间有什么区别?


dart的网站上有一个帖子,解释得很好。

最后:

"final"表示单赋值:final变量或字段必须有初始化式。一旦赋值,最终变量的值就不能更改。Final修改变量。


常量:

“const”在Dart中有一个更复杂和微妙的含义。Const用于修改值。你可以在创建集合时使用它,比如const[1,2,3],也可以在构造对象(而不是new)时使用它,比如const Point(2,3)。在这里,const意味着对象的整个深度状态可以完全在编译时确定,对象将被冻结并且完全不可变。

Const对象有几个有趣的属性和限制:

它们必须从可以在编译时计算的数据中创建。const对象不能访问运行时计算所需的任何内容。1 + 2是一个有效的const表达式,但new DateTime.now()不是。

它们是深刻的、传递的不可变的。如果final字段包含一个集合,则该集合仍然可以是可变的。如果你有一个const集合,它里面的所有东西也必须是const,递归地。

它们被规范化了。这有点像字符串实习:对于任何给定的const值,无论对const表达式求值多少次,都会创建一个const对象并重新使用。


那么,这意味着什么呢?

Const: If the value you have is computed at runtime (new DateTime.now(), for example), you can not use a const for it. However, if the value is known at compile time (const a = 1;), then you should use const over final. There are 2 other large differences between const and final. Firstly, if you're using const inside a class, you have to declare it as static const rather than just const. Secondly, if you have a const collection, everything inside of that is in const. If you have a final collection, everything inside of that is not final.

最后: 如果在编译时不知道Final的值,则应该在const上使用Final,并且它将在运行时计算/获取。如果你想要一个不可更改的HTTP响应,如果你想从数据库中获取一些东西,或者如果你想从本地文件中读取,请使用final。编译时不知道的任何东西都应该在const上使用final。


话虽如此,const和final都不能被重赋,但final对象中的字段,只要它们本身不是const或final,就可以被重赋(不像const)。


通过@Meyi扩展答案

final variable can only be set once and it is initialized when accessed.(for example from code section below if you use the value of biggestNumberOndice only then the value will be initialized and memory will be assigned). const is internally final in nature but the main difference is that its compile time constant which is initialized during compilation even if you don't use its value it will get initialized and will take space in memory. Variable from classes can be final but not constant and if you want a constant at class level make it static const.

代码:

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;
}

如果你来自c++,那么Dart中的const在c++中是constexpr,而Dart中的final在c++中是const。

以上内容仅适用于基本类型。 然而在Dart中,标记为final的对象在其成员方面是可变的。


合并@Meyi和@faisal-naseer的答案,并与小程序进行比较。

常量:

Const关键字,用于创建存储编译时常量值的变量。编译时常量值是一个在编译时为常量的值:-)

例如,5是一个编译时常数。而DateTime.now()不是编译时间常量。因为这个方法将返回行在运行时被执行的时间。所以我们不能将DateTime.now()赋值给一个const变量。

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();

应在同一行进行初始化。

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;

以下所有陈述均可接受。

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

类级别的const变量应该像下面这样初始化。

Class A {
    static const a = 5;
}

实例级const变量不可用。

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

const的另一个主要用途是使对象不可变。要使类对象不可变,我们需要使用const关键字和构造函数,并将所有字段设置为final,如下所述。

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);
}

我们可以对列表使用const关键字。

const a = const[] -初始化为const的变量a,它包含一个const对象的列表(例如:,列表应该只包含编译时间常量和不可变对象)。所以我们不能用另一个列表赋值a。

var a = const[] -初始化为var的变量a,其中包含一个const对象列表。所以我们可以将另一个列表赋值给变量a。

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关键字还用于使变量保持恒定值。一旦初始化,就不能更改值。

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

以下所有陈述均可接受。

// Without type or var
final a = 5;
// With a type
final int b = 5;
// Can't use var along with final keyword. Uncommenting below line cause compilation issue.
// final var c = 6;

能够分配运行时值。

// 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;

类级final变量必须在同一行中初始化。

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

实例级final变量必须在同一行或在构造函数初始化中初始化。该值将在创建对象时被放入内存中。

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);
}

分配一个列表。

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()];

常量

Value必须在编译时已知,const birthday = "2008/12/25"初始化后不能更改。


最后

值必须在运行时已知,最终生日= getBirthDateFromDB()初始化后不能更改。


final和const都防止变量被重新赋值(类似于Java中的final或JavaScript中的const)。

这种差异与内存的分配方式有关。在运行时为final变量分配内存,在编译时为const变量分配内存。最后一个修饰符应该是更常用的,因为许多程序变量不需要任何内存,因为程序逻辑不会调用它们进行初始化。对于一个const变量,你基本上是在告诉计算机,“嘿,我需要这个变量的内存,因为我知道我将会需要它。”

以这种方式思考它们可以更容易地理解它们在语法用法上的差异。主要是final变量可以是实例变量,而const必须是类上的静态变量。这是因为实例变量是在运行时创建的,而const变量(根据定义)不是。因此,类上的const变量必须是静态的,这意味着类上存在该变量的单个副本,而不管该类是否实例化。

这段视频相当简单地解释了这一点: https://www.youtube.com/watch?v=9ZZL3iyf4Vk

本文将更深入地讨论并解释两者之间非常重要的语义差异,即final修改变量而const修改值,这本质上归结为只能初始化编译时可派生的const值。

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


你不能使用final对象初始化const对象。例如:

  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

dart中的Final和const很容易混淆,以至于我们认为它们是相同的。

让我们来看看它们的区别:

附注:我包括图像而不是文本,因为我不能将信息制成表格 在Stackoverflow .md格式轻松。


何时使用哪个关键字?

一个简单的例子: 使用final:如果你不知道它在编译时的值是多少。例如,当您需要从API获取数据时,就会在运行代码时发生这种情况。

使用const:如果您确定在运行代码时不会更改某个值。例如,当你声明一个始终保持不变的句子。

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


Const表示它的初始值必须是固定的,不能是动态值;

Final意味着它的初始值必须是固定的,但可以是一个动态值,等于具有固定值的var。

代码演示

常量

void main() {
  const sum = 1 + 2;
  // ✅ const can not change its value
  print("sum = ${sum}");
  // ⚠️ Const variables must be initialized with a constant value.
  const time = new DateTime.now();
  // ❌ Error: New expression is not a constant expression.
  print("time = ${time}");
}

最后

// new DateTime.now();
// dynamic timestamp

void main() {
  final sum = 1 + 2;
  // ✅ final can not change its value
  print("sum = ${sum}");
  final time = new DateTime.now();
  // ✅ final === var with fixed value
  print("time = ${time}");
}

截图

refs

https://dart.dev/guides/language/language-tour#final-and-const


const是一个编译时常量。

final是一个运行时常数。


编译时不知道的任何东西都应该在const上使用final。


具有final关键字的变量将在运行时初始化,并且只能分配一次。

带有const关键字的变量在编译时初始化,在运行时已经赋值。

使用final:如果你不知道它在编译时的值是多少。例如,当您需要从API获取数据时,就会在运行代码时发生这种情况。 使用const:如果您确定在运行代码时不会更改某个值。例如,当你声明一个始终保持不变的句子。


所有这些答案我都可以用简洁的方式描述。

const list = [1, 2, 3];

变量/标识符和值都是const。Like - const list = const [1,2,3] 这就是为什么他们不允许被重新分配。 很适合全局变量。 可以将其用作类变量,但必须设置为静态。Like - static const list =[1,2,3]。

vs:

final list = [1, 2, 3];

变量/标识符是const,而值不是。Like - const list = [1,2,3] 这就是为什么我们可以执行like - list.add(4)


简单的单词:

常量

值必须在编译时已知,即来自内部文件的值。

示例:API键,应用程序支持的语言或helper文件中的任何变量,基本上是应用程序附带的任何东西。

最后

值必须在运行时已知。

它可以是上面的数据,也可以是设备信息,当应用程序启动时将被检查,或者当应用程序启动时从API或服务器加载的数据,但在应用程序准备使用之前,即你需要检查用户是否登录,你的应用程序将从服务器加载或检查会话令牌。


答案就在图像本身。