展開操做符 ...
可以把 list、set、map
字面量裏的元素插入到一個集合中。一個對象是否可用於展開操做符取決因而否繼承了Iterable
,Map集合例外,對 map 進行展開操做 其實是 調用了 Map
的 entries.iterator()
android
在實際開發中,咱們可能須要建立新的集合,集合的元素一般依賴另外一個已經存在集合,而後再次基礎上再添加寫新的元素,如:git
var args = testArgs.toList()
..add('--packages=${PackageMap.globalPackagesPath}')
..add('-rexpanded')
..addAll(filePaths);
複製代碼
上面的代碼案例,來自官網。其中 toList()
函數會建立一個新的集合,集合裏包含了 testArgs
全部元素 而後經過 級聯操做符
實現鏈式調用來簡化代碼,最後經過 addAll
添加另外一個集合的全部元素github
可是這種寫法依然很是笨重,下面來看下如何經過 展開操做符簡化代碼:json
var args = [
...testArgs, // 經過展開操做符將testArgs集合解包而後將裏面的元素逐個放進args裏
'--packages=${PackageMap.globalPackagesPath}',
'-rexpanded',
...filePaths // 經過展開操做符將filePaths集合解包而後將裏面的元素逐個放進args裏
];
複製代碼
在 Flutter
中是使用 聲明式UI(declarative style)
, Android/iOS
是使用 命令式UI(imperative style)
bash
什麼是 聲明式UI
? 在 Flutter
中,若是 Widget 發生變化經過 setState
函數觸發,而後 Flutter 會構建新的 Widget 實例和 Widget 子樹 而 命令式UI
是拿到原來的 Widget 實例,而後調用該實例的方法來觸發變化,而不是建立新的 Widgetfrontend
他們之間的代碼風格區別以下:函數
// 聲明式UI代碼風格
return ViewB(
color: red,
child: ViewC(...),
)
// 命令式UI代碼風格
b.setColor(red)
b.clearChildren()
ViewC c3 = new ViewC(...)
b.add(c3)
複製代碼
展開操做符
在 Flutter 這種聲明式 UI 中應用很是普遍,例如咱們構建一個 ListView:oop
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: ListView(
children: [ //children 就是一個List
Tab2Header(),
// buildTab2Conversation()返回值也是一個List
...buildTab2Conversation(),
],
),
);
}
複製代碼
上面的例子是在 List 中和使用展開操做符,在 Map 集合中也是同樣的,例如將 queryParams 和 formParams 合併產生一個新的 Map 集合學習
var map = {
...options.queryParameters,
...options.data
};
複製代碼
在 Set 中的使用展開操做符也同樣的,如:ui
var items = [2, 3, 4];
var set = { 1, 2, ...items };
複製代碼
上面的咱們講到的展開操做符,若是被展開的對象是 null,那麼會拋出運行時異常
var oops = null;
//NoSuchMethodError: The getter 'iterator' was called on null
var list = [...oops];
複製代碼
若是被展開的對象可能爲 null,須要在展開操做符後面加上 ?
號 (...?
):
var oops = null;
var list = [...?oops];
複製代碼
List 中使用展開操做符分析
var list = [elem_1 ... elem_n]
1. 首先會建立新的集合,用於保存集合字面量裏的元素
2. 遍歷字面量裏的全部元素
1)把元素表達式(展開操做符)賦值給value遍歷
2)若是遍歷的元素是展開操做符
a)若是使用的是可空的展開操做符,而且 value 是 null,直接 continue
b)將 value.iterator 賦值給 iterator 變量
c)而後遍歷 iterator,將裏面的元素追加到上面新建的集合裏
3)若是遍歷的元素不是展開操做符,直接將元素添加到集合中
3. 就這樣,集合字面量的元素所有在上面新建的集合裏了
複製代碼
像其餘的集合如 Set、Map 也是相似的機制
控制流集合
就是在構建集合字面量的時候能夠使用 if、for
控制流語句,簡稱 collection-if/for
上面咱們提到 Flutter 是聲明式 UI,例如:
Widget build(BuildContext context) {
return Row(
children: [ // 集合字面量
IconButton(icon: Icon(Icons.menu)),
Expanded(child: title),
IconButton(icon: Icon(Icons.search)),
],
);
}
複製代碼
若是咱們想在上面的代碼的基礎上加一些判斷,例如只在 Android 平臺展現搜索按鈕(Icons.search),咱們可能會這麼寫:
Widget build(BuildContext context) {
// 構建button集合
var buttons = <Widget>[
IconButton(icon: Icon(Icons.menu)),
Expanded(child: title),
];
// 若是是 android 平臺,添加搜索按鈕
if (isAndroid) {
buttons.add(IconButton(icon: Icon(Icons.search)));
}
return Row(
children: buttons,
);
}
複製代碼
有了 Control Flow Collection
,咱們能夠這樣類簡化代碼:
Widget build(BuildContext context) {
return Row(
children: [
IconButton(icon: Icon(Icons.menu)),
Expanded(child: title),
// 若是是 android 平臺,添加搜索按鈕
if (isAndroid) IconButton(icon: Icon(Icons.search)),
]
);
}
複製代碼
除了使用 if
,還能夠使用 else
,例如在 Android 平臺展現搜索按鈕
, 其餘平臺展現關於按鈕
:
Widget build(BuildContext context) {
return Row(
children: [
IconButton(icon: Icon(Icons.menu)),
Expanded(child: title),
if (isAndroid)
IconButton(icon: Icon(Icons.search))
else
IconButton(icon: Icon(Icons.about)),
]
);
}
複製代碼
再好比咱們須要根據一個集合而後生成另外一個集合,可能會這樣寫:
var command = [
engineDartPath,
frontendServer,
];
for (var root in fileSystemRoots) {
command.add('--filesystem-root=$root');
}
for (var entryPointsJson in entryPointsJsonFiles) {
if (fileExists("$entryPointsJson.json")) {
command.add(entryPointsJson);
}
}
command.add(mainPath);
複製代碼
有了 Control Flow Collection
,咱們能夠這樣寫,可讀性更強:
var command = [
engineDartPath,
frontendServer,
for (var root in fileSystemRoots) '--filesystem-root=$root',
for (var entryPointsJson in entryPointsJsonFiles)
if (fileExists("$entryPointsJson.json")) entryPointsJson,
mainPath
];
複製代碼
還能夠在構建集合字面量的時候 for
循環計算:
var integers = [for (var i = 1; i < 5; i++) i]; // [1, 2, 3, 4]
var squares = [for (var n in integers) n * n]; // [1, 4, 9, 16]
複製代碼
構建 Map
字面量的時候,咱們可能會這樣寫:
Map<String, WidgetBuilder>.fromIterable(
kAllGalleryDemos,
key: (demo) => '${demo.routeName}',
value: (demo) => demo.buildRoute,
);
複製代碼
collection-for
可讓咱們的代碼簡化成以下所示:
return {
for (var demo in kAllGalleryDemos)
'${demo.routeName}': demo.buildRoute,
};
複製代碼
collection if-for
還能夠組合,例如 for
循環嵌套,for-if
嵌套:
//for-for
[for (var x in hor) for (var y in vert) Point(x, y)]
//for-if
[for (var i in integers) if (i.isEven) i * i]
複製代碼
Dart 的展開操做符
(Null-aware spread、Non-null-ware spread) 和 Control flow collections
(collection if/for)
讓咱們編寫的代碼的時候代碼的可讀性更高
特別是編寫 Flutter UI
的時候更符合 declarative style
代碼風格
從中能夠看出 Dart 代碼的表現力仍是很強的
關於 Dart 展開操做符 和 Control Flow Collections 就講到這裏, 更多的關於 Android
學習資料能夠查看個人GitHub: github.com/chiclaim/An…
flutter.dev/docs/get-st… github.com/dart-lang/l… github.com/dart-lang/l…
下面是個人公衆號,乾貨文章不錯過,有須要的能夠關注下,有任何問題能夠聯繫我: