回答这个问题前应该要先了解为什麽会有 null
,如果写过网页前端的读者应该很常看到以下程序码(以react举例)
if(!apiData){
return <></>
}
其实大部分原因都是因为「我们不确定什麽时候有值」。最常见大概就是来自後端的资料,至於为什麽这样会产生null
,正如前几篇文章说过非同步要等待一段时间才会回传结果,但为了执行绪不阻塞所以执行绪会继续往下执行程序。
所以有些 Component 必须额外做null check ,否则在 runtime 时就会有几秒值是null
但如果有Component 有取用这些值,就会发生runtime error,又或者是这次api request是失败的。但在response回来前我们根本不会知道这些事情。
在 Dart SDK 2.12 版後就是会预设开启 Sound null safety,其中最大的前提是
「如果没有特别说明所有的type都是non-nullable的」
所以我们现在如果真的有个Type有可能是 null 那我们可以用 Type?
来表示这个变数是nullable的,像是下面例子中的 String? apiData
class Foo {
String? apiData;
Future<void> fecthData() async {
await Future.delayed(Duration(seconds: 0), () {
apiData = 'hello wrold';
});
}
}
// ...
final foo = Foo()
foo.apiData.length // 这行会出错
所以当我们使用 foo.apiData.length
时,就会静态检查期间就有error出现:
而如果我们硬要run 就会直接跳出error
从这个例子我们就可以看到null safety 对我们开发有多大的帮助,因为我们不用实际run就可以知道哪部分的code可能会有null相关的runtime error。
那我们要怎麽操作nullable type的变数呢?
基本上有两种方式 ?
!
?.
就跟JS的optional chaining一样:如果存取到null就直接return null而不是直接throw error
print(foo.apiData?.length);
// null
!
则是表示这个变数「现在」一定不是null
我们先宣告一个input type 为 String
的function
String concatString(String input) => input + '---';
// ...
final foo = Foo();
await foo.fecthData();
concatString(foo.apiData);
concatString(foo.apiData!);
print(foo.apiData!.length);
会发现即使我们是在 fetchData()
後再取用 foo.apiData
这里的type 依然是 String?
,虽然我们能够确定他一定有值,但这是静态检查不出来的。所以我们可以加上!
让编译器知道:
「这个值虽然是nullable type,但它现在一定不是null哦」
所以我们就能将 原本是 String?
的变数放进去只接受 String
的function里,也能够正确的调用 .length
了。
还记得在很久很久之前看到的 late
吗
先在一个 class
中先用 final
宣告两个成员然後其中一个加上 late
:
late final String a;
final String b;
Test(this.b);
void setInitValue() {
a = 'a';
}
如果在constructor没有放this.b
会看到hint 只有跳出 b
需要 initialize
但late
只是可以让 null
检查延迟到运行而不是编译,所以如果忘记 initialize 在runtime还是会有error跳出来。
final test = Test('');
//test.setInitValue();
print(test.a);
今天的程序码:
https://github.com/zxc469469/dart-playground/tree/Day12/null-safety
Sound null safety 只是很大一部份提升我们在开发时体验,但这不代表一定不会有bug,毕竟你可能真的没有去set资料导致你之後!
其实是标爽的,又或者标 late
的变数忘记 initialize,另外还有一个好处就是会提升程序的编译效率,因为编译器可以少做一些null check。
而明天将是Dart篇的最後一篇文章,也就是稍微提一下 Functional programming(FP)的概念。之後就要进入Flutter的世界了~
参考资料:
https://juejin.cn/post/6958965184631144478
<<: Day 25 - [实战练习] 使用 Plugin 建立 Form 注册表单
>>: 【Day 12】逻辑回归(Logistic Regression)(上)
前言 Repository 设计模式主要是要分离商业逻辑与资料存取的逻辑,希望开发者专注在商业逻辑的...
参赛动机 原本是职缺是应徵网页前端工程师,因为公司目前需要有人帮忙写 App ,就被推坑一起写 Fl...
忘了在哪看到很喜欢的一段话 每个我们生命中遇见的人 都在我们身上留下了一点影子 以前不懂 但後来发...
接着点选六个按钮(不要点选整个stack view),设定每个按钮的长宽和按钮与按钮的距离。 而後我...
WebRTC 通讯 WebRTC 最常见的应用场景就是一对一的视讯通话,当我们准备和另一端的人进行点...