likes
comments
collection
share

Dart 点将台 | const 关键字知多少

作者站长头像
站长
· 阅读数 16

本文有对应的视频版,可在 哔哩哔哩 进行观看: Flutter 梦始之地 - const关键字的一点点小细节

1.对 const 的认知

80% 的人对 const 的认知,只停留在 const 修饰的量不可以被修改,这一条。 甚至有些人对什么时候可以用 const 修饰还比较模糊。首先看一下内置的类型变量对象的构造,如 intdoubleString,这些类型的对象可以使用 const 修饰。一旦被 const 修饰的量,就无法再做更改。

Dart 点将台 |  const 关键字知多少


2.何时何处可以用 const 修饰

下面先看一下,什么时候能用 const,什么时候不能用 const。如下 Person 类中有一个 name 成员。 对于一个 Person 对象而已,是不能使用 const 修饰的。错误原因,红线处也有提示:

[1]. 无 const 构造方法创建的对象,无法使用 const 修饰。 

Dart 点将台 |  const 关键字知多少


既然提示说,想要 const 修饰对象,其对应构造需要为 const,那就在构造前加个 const 呗。这时你会发现上面的声明不飘红了,但下面的 const 修饰的构造方法飘红了。提示说 :

[2].使用 const 构造方法的类中,其所有成员属性必须以 final 修饰。

Dart 点将台 |  const 关键字知多少


所以这时将 namefinal 修饰,就可以不报错。从上面两点可以得出一个推论:

[推论]: 使用 const 修饰的对象,其各属性也是无法修改的。

Dart 点将台 |  const 关键字知多少

总结一下 const 可修饰的位置:在声明变量时,可以将 const 放在前面,也可以将 const 放在等号后,修饰构造函数;const 可作为修饰符,修饰构造函数。 只有在修饰 的时候,该 才不允许被修改。比如下面 toly2 可以赋为其他值,但 toly 不可以。

Dart 点将台 |  const 关键字知多少


3.const 在类中的注意点
[3]: const 构造方法不能有方法体。

Dart 点将台 |  const 关键字知多少

[4]: 类中的 const 修饰的成员,必须为 static 静态的。

Dart 点将台 |  const 关键字知多少

你在源码中可以看到,使用 const 修饰的成员,都会由 static 修饰。

Dart 点将台 |  const 关键字知多少


4.const 的价值

如下:a ,b 对象声明为 const,c 对象使用普通构造,可见 a 和 b 是全等的,由于没有在 Person 类中重写 == 运算符,则说明这两个量在 运行时 同一块内存地址。这样的好处在于:即使在代码中用了 10000 次 const Person(name: 'toly') ,都是同一对象,都是同一块内存空间。这便是 const 常量的优势,该对象在代码编译期间 就已经确定的。

而对于非 const 创建的对象,用了 10000 次 Person(name: 'toly') ,就是创建了 10000 个对象,每个对象都占着一份空间。 所以这样看来,对于一些不变的常量,使用 const 修饰是很有价值的。

main() {
  Person a = const Person(name: 'toly');
  Person b = const Person(name: 'toly');
  Person c = Person(name: 'toly');
  print(a == b); // true
  print(a == c); // false
}

5. const 常量在 Flutter 中的使用

这时,你再反观 Flutter 中的一些东西,就会有更多的感悟,比如 Text 组件的构造器使用了 const 修饰,就说明 Text 对象可以使用 const 进行修饰,并且 Text 类中的所有属性都必须为 final。

Dart 点将台 |  const 关键字知多少

这样,对应不变的文字信息,可以使用 const 进行修饰,这样,下次 build 时这个量就可以直接使用,而非构造新的 Text 对象。Flutter 中的很多组件和属性都有 const 构造,如果它们是不变的,最好使用 const 修饰。

const Text('张风捷特烈')

但要注意:const 是编译期常量,你不能在其中使用运行时的计算,这样编译是无法通过的。

Dart 点将台 |  const 关键字知多少


6.关于const 的层级

如下, Padding 及其属性都是常量,作用两边,是否等价?是否需要一一加 const

Dart 点将台 |  const 关键字知多少


这里来做一个小实验,在 Position 类中添加 Position 属性。 ab 对象构造如下,a 只用一个 const 修饰,b 每个对象都用 const 修饰。结果显示,a 和 b 是相等的 , a.positionb.position 也是相等的。这就说明,左右写法是一致的,所以没必要每个对象上都加 const 修饰。

main() {
  Person a = const Person(
    name: "张风捷特烈",
    position: Position(
      position: 4
    )
  );

  Person b = const Person(
      name: "张风捷特烈",
      position: const Position(
          position: 4
      )
  );

  print(a == b); // true
  print(a.position == b.position); // true
}

class Person {
  final String name;
  final Position position;
  const Person({this.name = '张风捷特烈',this.position});
}

class Position{
  final int position;
  const Position({this.position = 0});
}

越上层使用 const 要求是更严格的,其下都必须都是常量才可以。如下,TextStyle 中 color 使用了 withOpacity 方法,是运行时的,所以构造出的 TextStyle 就不是常量,最上层的 Padding 自然也就不能使用 const 修饰。

Dart 点将台 |  const 关键字知多少

同理这里 Text 也无法使用 const 修饰,所以,只能将 const 给 EdgeInsets.all(8.0) 修饰。也就是说,能用 const 修饰的尽量用 const 修饰。

Dart 点将台 |  const 关键字知多少

关于 const 在用法上的一些细节点,就讲到这里,FlutterUnit 之前没太注意这方面,现在已经优化完毕。现在你也该想一想,你的常量 const 了吗 ~ 下面小结一下:

[1]. 无 const 构造方法创建的对象,无法使用 const 修饰。 
[2]. 使用 const 构造方法的类中,其所有成员属性必须以 final 修饰。
[推论]: 使用 const 修饰的对象,其各属性也是无法修改的。
[3]. const 构造方法不能有方法体。
[4]: 类中的 const 修饰的成员,必须为 static 静态的。
[5]. const 构造方法中传入的值必须是 const 对象。

7. debug 模式下的 Dart 常量去重策略

昨天有人在群里问了 const 为什么在运行时不相等:

Dart 点将台 |  const 关键字知多少

因为 debug 模式 下的 Dart 常量去重策略导致的。在官网有相关介绍文章 《调试 Flutter 应用》。其实很容易理解,在 debug 时,需要追踪 Widget 的创建时机,而 const 对象在编译期间就已经初始化了。这是 debug 模式 下的 常量去重策略的必要性。当然你可以通过如下方式来关闭这个 去重策略 ,但一般来说这并没有什么必要。

flutter run --no-track-widget-creation

如下,在 release 模式下运行,就不会出现这种现象。App 的开发还是以 release 模式为准,所以不必太过纠结。

Dart 点将台 |  const 关键字知多少

转载自:https://juejin.cn/post/7091833861281153038
评论
请登录