本节指标
- 空平安意味着什么
- 如何迁徙代码
- 如何禁用空平安
- 代码标准示例
视频
https://www.bilibili.com/vide...
代码
https://github.com/ducafecat/...
参考
- https://dart.cn/null-safety
- https://dart.cn/null-safety/m...
- https://dart.cn/null-safety/u...
- https://dart.cn/null-safety/u...
- https://dart.cn/null-safety/faq
注释
空平安意味着什么
- 默认不可空
String title = 'ducafecat';
type?
操作符
String? title = null;
value!
操作符
String? title = 'ducafecat';String newTitle = title!;
value?
操作符
String? title = 'ducafecat';bool isEmpty = title?.isEmpty();
value??
操作符
String? title = 'ducafecat';String newTitle = title ?? 'cat';
late
会在运行时查看。所以请您仅在确定它被应用前肯定会被初始化的状况下应用
late String? title;title = 'ducafecat';
- List、泛型
类型 | 汇合是否可空 | 数据项是否可空 |
---|---|---|
List<String> | no | no |
List<String>? | yes | no |
List<String?> | no | yes |
List<String?>? | yes | yes |
- Map
类型 | 汇合是否可空 | 数据项是否可空 |
---|---|---|
Map<String, int> | no | no* |
Map<String, int>? | yes | no* |
Map<String, int?> | no | yes |
Map<String, int?>? | yes | yes |
*
可能返回空
// 有可能返回 nullint value = <String, int>{'one': 1}['one']; // ERROR// 须要加上 type?int? value = <String, int>{'one': 1}['one']; // OK// 或者 value!int value = <String, int>{'one': 1}['one']!; // OK
带来的益处
- 代码更衰弱
- 用户体验好
- 运行更快
- 编译文件更小
开启和迁徙
- pubspec.yaml
environment: sdk: ">=2.12.0 <3.0.0"
- 迁徙程序
咱们强烈建议您按程序迁徙代码,先迁徙依赖关系中的处于最末端的依赖。例如,如果 C 依赖了 B,B 依赖了 A,那么应该依照 A -> B -> C 的程序进行迁徙。
- 查看依赖我的项目
# Dart 版本是否为 2.12 或更高> dart --version# 依赖包的迁徙状态> dart pub outdated --mode=null-safety
- 降级依赖
# 该命令会更改您的 pubspec.yaml 文件> dart pub upgrade --null-safety# 升级包> dart pub upgrade
- 迁徙工具
> dart migrate
- 剖析
> dart analyze
禁用空平安
- cli 命令
> dart --no-sound-null-safety run> flutter run --no-sound-null-safety
- .vscode/launch.json
{ // 应用 IntelliSense 理解相干属性。 // 悬停以查看现有属性的形容。 // 欲了解更多信息,请拜访: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "getx_quick_start", "request": "launch", "type": "dart", "program": "lib/main.dart", "args": ["--no-sound-null-safety"] } ]}
范例、标准
https://dart.cn/null-safety/u...
- 明确解决空状态
makeCoffee(String coffee, [String? dairy]) { if (dairy != null) { print('$coffee with $dairy'); } else { print('Black $coffee'); }}
- 顶层变量和动态字段必须蕴含一个初始化办法。因为它们能在程序里的任何地位被拜访到,编译器无奈保障它们在被应用前已被赋值。惟一保险的选项是要求其自身蕴含初始化表达式,以确保产生匹配的类型的值。
int topLevel = 0;class SomeClass { static int staticField = 0;}
- 实例的字段也必须在申明时蕴含初始化办法,能够为常见初始化模式,也能够在实例的构造方法中进行初始化。
class SomeClass { int atDeclaration = 0; int initializingFormal; int initializationList; SomeClass(this.initializingFormal) : initializationList = 0;}
- 局部变量的灵便度最高。一个非空的变量 不肯定须要 一个初始化办法。
int tracingFibonacci(int n) { int result; if (n < 2) { result = n; } else { result = tracingFibonacci(n - 2) + tracingFibonacci(n - 1); } print(result); return result;}
- 流程剖析,在这里 Dart 将
object
的类型从它申明的Object
晋升到了List
。在空平安引入以前,上面的程序无奈运行。
// With (or without) null safety:bool isEmptyList(Object object) { if (object is List) { return object.isEmpty; // <-- OK! } else { return false; }}->// Without null safety:bool isEmptyList(Object object) { if (object is! List) return false; return object.isEmpty;}
- 相对的赋值剖析
int tracingFibonacci(int n) { final int result; if (n < 2) { result = n; } else { result = tracingFibonacci(n - 2) + tracingFibonacci(n - 1); } print(result); return result;}
- 无用代码的正告
String checkList(List list) { if (list?.isEmpty) { return 'Got nothing'; } return 'Got something';}
- 懒加载的变量,
late
修饰符是“在运行时而非编译时对变量进行束缚”。这就让late
这个词语约等于 何时 执行对变量的强制束缚。
// Using null safety:class Coffee { String? _temperature; void heat() { _temperature = 'hot'; } void chill() { _temperature = 'iced'; } String serve() => _temperature! + ' coffee';}->// Using null safety:class Coffee { late String _temperature; void heat() { _temperature = 'hot'; } void chill() { _temperature = 'iced'; } String serve() => _temperature + ' coffee';}
late
与final
联合应用,与一般的final
字段不同,您不须要在申明或结构时就将其初始化。您能够稍后在运行中的某个中央加载它。然而您只能对其进行 一次 赋值,并且它在运行时会进行校验。
// Using null safety:class Coffee { late final String _temperature; void heat() { _temperature = 'hot'; } void chill() { _temperature = 'iced'; } String serve() => _temperature + ' coffee';}
- 毕传参数,这里的所有参数都必须通过命名来传递。参数
a
和c
是可选的,能够省略。参数b
和d
是必须的,调用时必须传递。在这里请留神,是否必须和是否可空无关。
// Using null safety:function({int? a, required int? b, int? c, required int? d}) {}
- 形象字段
abstract class Cup { Beverage get contents; set contents(Beverage);}->abstract class Cup { abstract Beverage contents;}
- 一些赋值计算能够挪动到动态的初始化中。
// Initalized without valuesListQueue _context;Float32List _buffer;dynamic _readObject;Vec2D(Map<String, dynamic> object) { _buffer = Float32List.fromList([0.0, 0.0]); _readObject = object['container']; _context = ListQueue<dynamic>();}->// Initalized with valuesfinal ListQueue _context = ListQueue<dynamic>();final Float32List _buffer = Float32List.fromList([0.0, 0.0]);final dynamic _readObject;Vec2D(Map<String, dynamic> object) : _readObject = object['container'];
- 可能返回
null
的工厂办法
factory StreamReader(dynamic data) { StreamReader reader; if (data is ByteData) { reader = BlockReader(data); } else if (data is Map) { reader = JSONBlockReader(data); } return reader;}->factory StreamReader(dynamic data) { if (data is ByteData) { // Move the readIndex forward for the binary reader. return BlockReader(data); } else if (data is Map) { return JSONBlockReader(data); } else { throw ArgumentError('Unexpected type for data'); }}
© 猫哥
本视频文档
https://ducafecat.tech/2021/0...
GetX Quick Start 代码
https://github.com/ducafecat/...
新闻客户端代码
https://github.com/ducafecat/...
strapi 手册译文
https://getstrapi.cn
微信探讨群 ducafecat
往期视频
- Dart 编程语言根底
https://space.bilibili.com/40... - Flutter 零根底入门
https://space.bilibili.com/40... - Flutter 实战从零开始 新闻客户端
https://space.bilibili.com/40... - Flutter 组件开发
https://space.bilibili.com/40... - Flutter 组件开发
https://space.bilibili.com/40... - Flutter Bloc
https://space.bilibili.com/40... - Flutter Getx4
https://space.bilibili.com/40... - Docker Yapi
https://space.bilibili.com/40...