【问题标题】:What is the difference between the "const" and "final" keywords in Dart?Dart 中的“const”和“final”关键字有什么区别?
【发布时间】:2018-10-30 01:26:28
【问题描述】:

Dart 中 constfinal 关键字有什么区别?

【问题讨论】:

  • 这里有一些关于const的细节:stackoverflow.com/questions/51576209/…和对final的简单解释是不变的(一旦用final关键字创建就不能重新赋值或赋值),你必须初始化一次。

标签: dart constants keyword final


【解决方案1】:

There is a post on dart's website and it explains it pretty well.

决赛:

“final”表示单一赋值:final 变量或字段必须有一个初始化器。一旦分配了一个值,最终变量的值就不能更改。 final 修改变量


常量:

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

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

它们必须由可在编译时计算的数据创建。 const 对象无权访问您在运行时需要计算的任何内容。 1 + 2 是有效的 const 表达式,但 new DateTime.now() 不是。

它们是深刻的、传递性的不可变的。如果您有一个包含集合的最终字段,则该集合仍然可以是可变的。如果您有一个 const 集合,则其中的所有内容也必须是 const 递归的。

它们是规范化的。这有点像字符串实习:对于任何给定的 const 值,无论 const 表达式被计算多少次,都将创建和重复使用单个 const 对象。


那么,这是什么意思?

常量:
如果您拥有的值是在运行时计算的(例如new DateTime.now()),您可以为其使用 const。但是,如果该值在编译时已知 (const a = 1;),那么您应该使用 const 而不是 finalconstfinal 之间还有另外两个很大的区别。首先,如果您使用const,则必须将其声明为static const 而不仅仅是const。其次,如果你有一个const 集合,那么其中的所有内容都在const 中。如果您有一个 final 集合,那么其中的所有内容不是 final

Final:
如果您在编译时不知道该值,则应使用final 而不是const,它将在运行时计算/获取。如果您想要一个无法更改的 HTTP 响应,如果您想从数据库中获取某些内容,或者如果您想从本地文件中读取,请使用 final。任何在编译时未知的东西都应该是final 而不是const


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

【讨论】:

  • const 关键字用于表示编译时常量。使用 const 关键字声明的变量是隐式 final 的。
  • @CopsOnRoad 你可以看看这个视频Dart Const vs Final
  • 最后一句话总结得真好。谢谢你。
  • 我们是否应该关心 const 是一个选项?性能提升真的很明显吗?
  • 所以这段代码:void main() { var fruits = ['apples', 'bananas', 'oranges']; for ( final fruit in fruits) { print('I like to eat $fruit'); } } 会一直打印一样吗?
【解决方案2】:

常量

值必须在编译时知道const birthday = "2008/12/25"
初始化后无法更改。


决赛

值必须在运行时已知,final birthday = getBirthDateFromDB()
初始化后无法更改。

【讨论】:

  • 简洁明了。史诗般的例子的最佳答案。谢谢。
【解决方案3】:

整合了@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;

类级常量变量应该像下面这样初始化。

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 [] - 变量a 初始化为const,其中包含const 对象的列表(即,该列表应仅包含编译时常量和不可变对象)。所以我们无法将a 分配给另一个列表

var a = const [] - 变量a 初始化为var,其中包含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;

类级最终变量必须在同一行初始化。

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

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

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

【讨论】:

  • 这是迄今为止最好的答案!它还演示了定义为文字的 const 集合,这是一个没有人介绍的重要案例。
  • const immutableObja = const A(5, 6); 也可以写成const immutableObja = A(5, 6);,因为智能 Dart 编译器会选择 const A(5,6) 而不是 new A(5,6)
  • 其实final var c = 6;是不允许的。声明的成员不能同时声明为finalvar
  • @StefanRein 正如您所提到的,var 不应与 final 一起使用。也更新了答案。感谢您的意见。
【解决方案4】:

@Meyi 扩展答案

  • final 变量只能设置一次,并在 访问。(例如,从下面的代码部分中,如果您只使用 biggestNumberOndice 的值,则该值将被初始化并分配内存)。
  • 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;
}

【讨论】:

  • 我认为问这个问题的更好方法是什么时候更喜欢运行时初始化而不是编译时初始化......
  • 为此,您可以咨询@Meyi 的答案,也可以访问他的帖子中的文章链接,非常棒:)
【解决方案5】:

dart 中的 finalconst 令人困惑,我们认为它们是相同的。

让我们看看他们的区别:

附:我包含了图像而不是文本,因为我无法将信息制成表格 轻松使用 Stackoverflow .md 格式。

【讨论】:

    【解决方案6】:

    我的理解

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

    截图

    参考

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

    【讨论】:

      【解决方案7】:

      finalconst 都防止变量被重新分配(类似于 final 在 Java 中的工作方式或 const 在 JavaScript 中的工作方式)。

      区别在于内存的分配方式。在运行时为final 变量分配内存,在编译时为const 变量分配内存。 final 修饰符应该是更常用的,因为许多程序变量不需要任何内存,因为程序逻辑不会调用它们来初始化它们。使用const 变量,您基本上是在告诉计算机,“嘿,我需要预先存储这个变量的内存,因为我知道我会需要它。”

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

      这个视频很简单地分解了它: https://www.youtube.com/watch?v=9ZZL3iyf4Vk

      本文更深入并解释了两者之间非常重要的语义差异,即final 修改变量和const 修改值,本质上归结为只能初始化const 可导出的值在编译时。

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

      【讨论】:

        【解决方案8】:

        如果您来自C++,则Dart 中的constC++ 中的constexprDart 中的finalC++ 中的const

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

        【讨论】:

        • 有点。我认为您可以对原始类型这么说,但对于对象却不行。 C++ 中的const 几乎总是用于指定对象不能通过特定的引用或指针改变。 Dart 中的final 不会阻止对象通过该变量进行变异。
        【解决方案9】:

        需要 TLDR 的 TLDR 吗? :)

        编译时未知的任何内容都应该是final 而不是const

        【讨论】:

          【解决方案10】:

          什么时候使用哪个关键字?

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

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

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

          【讨论】:

            【解决方案11】:

            const 是编译时常量。

            final 是一个运行时常量。

            【讨论】:

              【解决方案12】:

              如果您从不打算更改变量,请使用 finalconst,代替 var 或作为类型的补充。 final 变量只能设置一次; const 变量是编译时常量。 (常量变量是隐式最终的。)最终的顶级或类变量在第一次使用时被初始化。

              以下是创建和设置final 变量的示例:

              final name = 'Bob'; // Without a type annotation
              final String nickname = 'Bobby';
              

              您不能更改 final 变量的值:

              name = 'Alice'; // Error: a final variable can only be set once.
              

              const 用于您希望成为编译时常量的变量。如果const 变量在类级别,则将其标记为static const。在声明变量的地方,将值设置为编译时常量,例如数字或字符串文字、const 变量或对常量进行算术运算的结果:

              const bar = 1000000; // Unit of pressure (dynes/cm2)
              const double atm = 1.01325 * bar; // Standard atmosphere
              

              const 关键字不仅仅用于声明常量变量。您还可以使用它来创建常量值,以及声明创建常量值的构造函数。任何变量都可以有一个常量值。

              var foo = const [];
              final bar = const [];
              const baz = []; // Equivalent to `const []`
              

              您可以在 const 声明的初始化表达式中省略 const,例如上面的 baz。详情请见DON’T use const redundantly

              您可以更改非最终、非常量变量的值,即使它曾经具有 const 值:

              foo = [1, 2, 3]; // Was const []
              

              您不能更改 const 变量的值:

              baz = [42]; // Error: Constant variables can't be assigned a value.
              

              您可以定义使用type checks and castsisas)、collection ifspread operators(...和...?)的常量:

              const Object i = 3; // Where i is a const Object with an int value...
              const list = [i as int]; // Use a typecast.
              const map = {if (i is int) i: "int"}; // Use is and collection if.
              const set = {if (list is List<int>) ...list}; // ...and a spread.
              

              有关使用 const 创建常量值的详细信息,请参阅ListsMapsClasses

              【讨论】:

                【解决方案13】:

                带有final关键字的变量会在运行时初始化,并且只能赋值一次。

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

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

                【讨论】:

                  【解决方案14】:

                  我可以简明扼要地描述所有这些答案。

                  const list = [1, 2, 3];
                  
                  • 变量/标识符和值都是常量。喜欢-const list = const [1, 2, 3]
                  • 这就是他们不允许重新分配的原因。
                  • 非常适合全局变量。
                  • 可以将其用作类变量,但必须设置为静态。喜欢 - static const list = [1, 2, 3]

                  对比:

                  final list = [1, 2, 3];
                  
                  • 变量/标识符是 const 但值不是。喜欢-const list = [1, 2, 3]
                  • 这就是为什么我们可以像 - list.add(4)

                  【讨论】:

                    【解决方案15】:

                    您不能使用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
                    

                    【讨论】:

                      猜你喜欢
                      • 2015-07-28
                      • 2020-01-24
                      • 2013-10-28
                      • 2013-07-12
                      • 2015-05-11
                      • 2019-03-28
                      • 2012-11-14
                      • 1970-01-01
                      相关资源
                      最近更新 更多