Dart 空安全:
- 空类型操作符 (?)
- 空值合并操作符 (??)
- 空值断言操作符 (!)
- 延迟初始化 (late)
1、空类型操作符 (?)
- 当你想要根据一个表达式是否为 null 来执行某个操作时,你可以使用 (?)
- 语法:expression1?.expression2
- 如果 expression1 不是 null,则执行 expression2 并返回其结果。如果 expression1 是 null,则直接返回 null,并且不会执行 expression2。
String? name;int? length = name?.length;
// 如果 name 是 null,length 也会是 null
// 如果 name 不是 null,length 将会是 name 的长度
2、空值合并操作符 (??)
- 当你想要为一个可能为 null 的表达式提供一个默认值时,你可以使用 (??)
- 语法:expression1 ?? expression2
- 如果 expression1 不是 null,则返回 expression1 的值。如果 expression1 是 null,则返回 expression2 的值。
String? name = getName();
String fullName = name ?? "Unknown";
// 如果 name 是 null,则 fullName 为 "Unknown"
// 如果 name 不是 null,则 fullName 为 name 的值
3、空值断言操作符 (!)
- 当你确定一个表达式不应该为 null,但编译器无法确定时,你可以使用!来告诉编译器你确信该表达式不是 null
- 语法:expression!
- 使用此操作符时,你应确保表达式确实不是 null,否则在运行时会出现 NullPointerException
String? name = getName();
int length = name!.length;
// 确信 name 不是 null,并获取其长度
// 如果 name 是 null,则会报错 NullPointerException
补充,(!) 取反用法
void main(){String name = "leon";if(name is! String){print("其他类型");}else{print("String类型");}
}
//输出:String类型
4、延迟初始化 (late)
- 当你在声明变量时使用 late 关键字,你告诉 Dart 编译器该变量将在稍后的某个时间点被初始化,而不是在声明时立即初始化
void main() { late String name; // 声明一个late变量,此时不需要初始化 if (someCondition) { name = 'Alice'; // 在某个条件满足时进行初始化 } else { name = 'Bob'; // 在另一个条件满足时进行初始化 } print(name); // 使用已经初始化的变量
} bool someCondition = true; // 假设这是某个条件,实际情况中可能根据逻辑判断来设置
- 在 Flutter 中 State 的 initState 方法中初始化的一些变量,是比较适合使用 late 来进行延时初始化的
- 因为在 Widget 生命周期中 initState 方法是最先执行的,所以它里面初始化的变量通过 late 修饰后既能保障使用时的便利,又能防止空异常
class _TravelPgeState extends State<TravelPge> with TickerProviderStateMixin {late TabController _controller;void initState() {super.initState();_controller = TabController(length: 0, vsync: this);}...
5、补充:Widget 生命周期
- 在 Flutter 中,Widget 并不直接具有生命周期,因为 Widget 是不可变的(immutable)
- 然而,Flutter 中的 StatefulWidget 和 State 对象确实具有生命周期,因为 StatefulWidget 可以创建和管理一个可变的状态对象(State)
当你插入一个 StatefulWidget 到 Flutter 的 widget 树时,Flutter 会进行以下操作:
创建(Create):
- StatefulWidget 的实例被创建
- createState() 方法被调用以创建一个新的 State 对象
- initState() 方法在 State 对象上被调用,你可以在这里进行初始化操作
插入(Insert):
- StatefulWidget 和它的 State 对象被插入到 widget 树中
- build() 方法在 State 对象上被调用,以构建 widget 树
更新(Update):
- 当 StatefulWidget 的依赖项发生变化时,Flutter 会重新构建 widget 树
- build() 方法会再次被调用,但 State 对象不会改变
- 如果你想根据新的依赖项更新 State,你可以调用 setState(() {}),这将导致 build() 方法再次被调用,但 initState() 不会被调用
移除(Remove):
- 当 StatefulWidget 从 widget 树中移除时,Flutter 会调用 dispose() 方法。你可以在这里释放任何资源或执行任何必要的清理操作
注意,build() 方法在整个生命周期中可能会被多次调用,而 initState() 和 dispose() 方法每个 State 对象只会被调用一次。
class LifecycleWidget extends StatefulWidget { _LifecycleWidgetState createState() => _LifecycleWidgetState();
} class _LifecycleWidgetState extends State<LifecycleWidget> { void initState() { super.initState(); print('initState called'); // 初始化代码 } Widget build(BuildContext context) { print('build called'); return Container( padding: const EdgeInsets.all(16.0), child: Text('Lifecycle Widget'), ); } void dispose() { super.dispose(); print('dispose called'); // 清理代码 }
}
- 在这个例子中,当你插入 LifecycleWidget 到 Flutter 应用中时,你会看到 “initState called” 和 “build called” 打印出来
- 如果依赖项发生变化并触发重建,只有 “build called” 会再次打印
- 当你从 widget 树中移除 LifecycleWidget 时,“dispose called” 会打印出来。