Dart中的“ const”和“ final”关键字有什么区别?


Answers:


234

dart网站上有一篇文章,解释得很好。

最后:

“最终”表示单分配:最终变量或字段必须具有初始化程序。一旦分配了值,最终变量的值将无法更改。final修改变量


缺点:

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

常量对象具有一些有趣的属性和限制:

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

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

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


那么这是什么意思?

常量:
如果您拥有的值是在运行时计算的(new DateTime.now()例如,),则不能为其使用常量。但是,如果在编译时(const a = 1;)知道该值,则应使用constover finalconst和之间还有2个其他大差异final。首先,如果您使用const,则必须将其声明为,static const而不是just const。其次,如果您有一个const收藏夹,则其中的所有内容都在中const。如果您有一个final收藏,里面的所有东西都不是 final

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


话虽如此,两个constfinal都不能重新分配,但是final对象中的字段,只要不是constfinal,就可以重新分配(与不同const)。


3
const关键字用于表示编译时常量。使用const关键字声明的变量是隐式最终的。
阿伦·乔治

1
@Meyi,我们什么时候应该使用const以及何时final?您知道这些修饰符的某种用例吗?
CopsOnRoad '18

4
@CopsOnRoad,您可以在Dart Const vs Final
Lemuel Ogbunude '18

2
最后一句话确实很好地总结了这一点。感谢那。
Yster

我们甚至应该关心const是一个选择吗?性能提升真的可以察觉吗?
CodeGrue


43

合并了@Meyi和@ faisal-naseer答案,并且与很少的编程比较。

const:

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 []- 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;
// With var
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()];

20

通过@Meyi扩展答案

  • final变量只能设置一次,并且在访问时将被初始化。(例如,如果使用 biggestNumberOndice only的值,则将初始化该值并分配内存)。
  • const本质上是内部最终的,但是主要区别在于,即使在不使用其值的情况下,在编译过程中初始化的其编译时间常数也将被初始化并占用内存空间。

  • 类中的变量可以是最终变量,但不能是常量,如果要在类级别使用常量,请将其设置为静态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;
}

2
我认为提出这个问题的更好方法是,何时更喜欢运行时初始化而不是编译时初始化....
Faisal Naseer

为此,您可以咨询@Meyi答案,也可以从他的帖子中访问文章的链接,其妙妙之处:)
Faisal Naseer

2

两者finalconst阻止重新分配变量(类似于finalJava中的工作方式或constJavaScript中的工作方式)。

差异与内存分配方式有关。final在运行时为变量分配内存,const在编译时为变量分配内存。该final修改应该是比较常用的,因为很多程序变量不需要任何内存,因为程序逻辑不会打电话对它们进行初始化。有了const变量,您基本上是在告诉计算机:“嘿,我需要该变量的内存,因为我知道我将需要它。”

以这种方式思考它们可以更容易地理解其语法用法上的差异。主要是final变量可以是实例变量,但a 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


2

finalconst在dart中,混淆的程度达到了我们认为它们相同的程度。

让我们看看它们的区别:

PS我包括图像而不是文本,因为我无法轻松地以Stackoverflow .md格式制表信息。


1

如果您来自哪里C++,然后constDartconstexprC++finalDartconstC++

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


2
有点。我认为您可以针对原始类型而不是针对对象说。 const在C ++中,几乎总是使用C ++来指定对象不可通过特定的引用或指针进行更改。final在Dart中,它不会阻止对象通过该变量进行突变。
jamesdlin

0

您无法const使用来初始化final。例如 :

  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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.