詳解Flutter中Dart集合使用教程
前言
集合是應(yīng)用程序中最為常見的數(shù)據(jù)結(jié)構(gòu),Dart 一共支持如下四種集合,其中核心的 List
, Map
和 Set
在基礎(chǔ)框架中,而 Queue
在 dart:collection
庫定義。
- 列表:也就是 List類,可動(dòng)態(tài)增長(zhǎng)的數(shù)組;
- key-value 集:即 Map<K, V> 類,用于存儲(chǔ)鍵值對(duì);
- 隊(duì)列:即 Queue類;
- 集合:即Set類,集合中的元素不可重復(fù)。
本篇介紹集合的最佳實(shí)踐。
優(yōu)先使用集合的特有語法
對(duì)于核心的集合類List
, Map
和 Set
,由于經(jīng)常使用,Dart 為這些類提供的內(nèi)置的語法來快速構(gòu)建這些集合對(duì)象。
//?推薦用法 var?points?=?<Point>[]; var?addresses?=?<String,?Address>{}; var?counts?=?<int>{}; //?不推薦 var?addresses?=?Map<String,?Address>(); var?counts?=?Set<int>();
集合還有一些特殊的用法,比如使用展開操作符(而且同時(shí)支持 ? 操作符判斷是否為空)將一個(gè)集合加入到另一個(gè)集合。同時(shí)還支持結(jié)合 if 和 for 來控制元素的加入。
//?推薦用法 var?arguments?=?[ ??...options, ??command, ??...?modeFlags, ??for?(var?path?in?filePaths) ????if?(path.endsWith('.dart')) ??????path.replaceAll('.dart',?'.js') ]; //?不推薦 var?arguments?=?<String>[]; arguments.addAll(options); arguments.add(command); if?(modeFlags?!=?null)?arguments.addAll(modeFlags); arguments.addAll(filePaths ????.where((path)?=>?path.endsWith('.dart')) ????.map((path)?=>?path.replaceAll('.dart',?'.js')));
上面的推薦用法其實(shí)除了展開操作符以外,使用 if 和 for 的并不常見。說實(shí)話,個(gè)人挺不習(xí)慣這種寫法的,感覺可讀性并不高。
不要使用.length 屬性判斷集合是不是為空
由于集合遵循的是 Iterable
協(xié)議,這個(gè)協(xié)議并不需要集合隨時(shí)知道它的長(zhǎng)度。因此調(diào)用.length
的時(shí)候,其實(shí)相當(dāng)于是遍歷了一遍,執(zhí)行速度是很低的。這是獲取 length
的實(shí)現(xiàn)方法:
int?get?length?{ ??assert(this?is!?EfficientLengthIterable); ??int?count?=?0; ??Iterator?it?=?iterator; ??while?(it.moveNext())?{ ????count++; ??} ??return?count; }
因此,更高效地判斷集合是否為空的做法是使用.isEmpty
或 .isNotEmpty
。
bool?get?isEmpty?=>?!iterator.moveNext();
因此,不要用.length == 0來判斷集合是否為空。
//?正確示例 if?(lunchBox.isEmpty)?return?'so?hungry...'; if?(words.isNotEmpty)?return?words.join('?'); //?錯(cuò)誤示例 if?(lunchBox.length?==?0)?return?'so?hungry...'; if?(!words.isEmpty)?return?words.join('?');
避免使用 forEach 迭代元素
在 JS 中,會(huì)使用 forEacth 方法來迭代元素,這是因?yàn)閮?nèi)置的 for-in 循環(huán)和我們想要的不一樣。但是在 Dart 中的 for-in 循環(huán)是正常的迭代,這樣會(huì)簡(jiǎn)化我們的代碼。
//?正確示例 for?(final?person?in?people)?{ ??... } //?錯(cuò)誤示例 people.forEach((person)?{ ??... });
但是如果我們是要對(duì)每個(gè)元素進(jìn)行操作的話,那么可以直接將這個(gè)操作作為方法傳遞到 forEacth
中,這樣的代碼更簡(jiǎn)潔。
people.forEach(print);
注意 Map
是不可迭代的,因此使用 forEach
是沒問題的。
不要使用 List.from(),除非你想要更改結(jié)果的類型
下面是兩行對(duì)比的代碼:
var?list?=?['a',?'b']; var?copy1?=?list.toList(); var?copy2?=?List.from(list); print(copy1.runtimeType); print(copy2.runtimeType);
猜猜打印出來的結(jié)果會(huì)是什么?
List<String>
List<dynamic>
如果使用 List.from
方法的話,如果不指定泛型類型,會(huì)抹除集合的類型,變成 dynamic
?。。∫虼?,除非某些對(duì)象需要做這樣的類型轉(zhuǎn)換,否則不應(yīng)該使用 List.from
方法。當(dāng)然,List.from
也不是沒有用,比如數(shù)值類型支持強(qiáng)制轉(zhuǎn)換,可以指定類型做強(qiáng)制轉(zhuǎn)換,例如下面剩下的因?yàn)槎际钦麛?shù)了,因此可以轉(zhuǎn)為 List類型``。
var?numbers?=?[1,?2.3,?4];?//?List<num>. numbers.removeAt(1);?//?Now?it?only?contains?integers. var?ints?=?List<int>.from(numbers);
使用 whereType 過濾類型
如果要從動(dòng)態(tài)集合篩選某個(gè)類型的子集,那么應(yīng)該使用 whereType<T>
方法,而不是使用 where
來過濾。
var?list?=?['1',?'2',?1,?2]; //?正確示例 var?intList?=?list.whereType<int>(); //?錯(cuò)誤示例 var?intList?=?list.where((e)?=>?e?is?int);
這是因?yàn)椋?code>where 方法返回的仍然是一個(gè) WhereIterable<Object>
對(duì)象,而不是我們想要的WhereIterable<int>
對(duì)象,這意味如果使用 where
還需要做一次強(qiáng)制轉(zhuǎn)換,這并不推薦。
//?錯(cuò)誤示例 var?list?=?['1',?'2',?1,?2]; var?intList?=?list.where((e)?=>?e?is?int).cast<int>();
如果有別的方式的話,不要使用 cast 做強(qiáng)制轉(zhuǎn)換
通常,當(dāng)在處理迭代對(duì)象或 stream
的時(shí)候,我們會(huì)對(duì)其做一系列的操作。之后,我們會(huì)指定一個(gè)類型的對(duì)象。相對(duì)于使用 cast()
方法,我們應(yīng)該使用其他可能存在的轉(zhuǎn)換方式。例如,當(dāng)我們使用 toList 的時(shí)候,可以使用 List<T>.from
來進(jìn)行類型轉(zhuǎn)換。
//?正確示例 var?stuff?=?<dynamic>[1,?2]; var?ints?=?List<int>.from(stuff); //?錯(cuò)誤示例 var?stuff?=?<dynamic>[1,?2]; var?ints?=?stuff.toList().cast<int>();
我們也可以使用 map<T>
來將集合轉(zhuǎn)為另一個(gè)類型的集合。
//?正確示例 var?stuff?=?<dynamic>[1,?2]; var?reciprocals?=?stuff.map<double>((n)?=>?1?/?n); //?錯(cuò)誤示例 var?stuff?=?<dynamic>[1,?2]; var?reciprocals?=?stuff.map((n)?=>?1?/?n).cast<double>();
避免使用 cast() 做強(qiáng)制轉(zhuǎn)換
當(dāng)我們沒有其他辦法進(jìn)行類型轉(zhuǎn)換時(shí),那么也需要盡可能地避免使用 cast()
做類型轉(zhuǎn)換。這里有幾條建議能夠避免使用強(qiáng)制轉(zhuǎn)換:
正確地定義集合類型,如果集合類型是明確的,那么就應(yīng)該在集合對(duì)象定義時(shí)明確類型。例如下面的例子:
//?正確示例 List<int>?singletonList(int?value)?{ ??var?list?=?<int>[]; ??list.add(value); ??return?list; } //?錯(cuò)誤示例 List<int>?singletonList(int?value)?{ ??var?list?=?[];?//?List<dynamic>. ??list.add(value); ??return?list.cast<int>(); }
在訪問元素時(shí)進(jìn)行轉(zhuǎn)換,當(dāng)進(jìn)行集合迭代的時(shí)候,可以在迭代過程中對(duì)每個(gè)元素進(jìn)行類型轉(zhuǎn)換。
//?正確示例 void?printEvens(List<Object>?objects)?{ ??//?假設(shè)我們知道集合只有整數(shù) ??for?(final?n?in?objects)?{ ????if?((n?as?int).isEven)?print(n); ??} } //?錯(cuò)誤示例 void?printEvens(List<Object>?objects)?{ ??//?假設(shè)我們知道集合只有整數(shù) ??for?(final?n?in?objects.cast<int>())?{ ????if?(n.isEven)?print(n); ??} }
優(yōu)先使用 List.from()
做轉(zhuǎn)換。如果集合的大部分元素都會(huì)被訪問到,而且不再需要對(duì)轉(zhuǎn)換前的做處理,那么就使用 List.from
來做轉(zhuǎn)換。cast()方法返回的是一個(gè)延遲處理的集合,當(dāng)需要使用元素時(shí)才會(huì)執(zhí)行轉(zhuǎn)換。對(duì)于轉(zhuǎn)換少量元素而言,這樣效率會(huì)高。但是,大部分情況下,將對(duì)象包裝為延遲對(duì)象的缺陷更明顯。
//?正確示例 int?median(List<Object>?objects)?{ ??//?假設(shè)我們知道集合只有整數(shù) ??var?ints?=?List<int>.from(objects); ??ints.sort(); ??return?ints[ints.length?~/?2]; } //??錯(cuò)誤示例 int?median(List<Object>?objects)?{ ??//?假設(shè)我們知道集合只有整數(shù) ??var?ints?=?objects.cast<int>(); ??ints.sort(); ??return?ints[ints.length?~/?2]; }
總結(jié)
本篇總結(jié)了 Dart 語言中使用集合的一些場(chǎng)景的最佳實(shí)踐,實(shí)際上很多要點(diǎn)我們?cè)谄綍r(shí)并不會(huì)注意 —— 抱著能用就行了的態(tài)度。但是,這些內(nèi)容官方早就有了指引,知道何為正確會(huì)有助于我們編寫質(zhì)量更高的代碼!
以上就是詳解Flutter中Dart集合使用教程的詳細(xì)內(nèi)容,更多關(guān)于Flutter Dart集合的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android開發(fā)實(shí)現(xiàn)AlertDialog中View的控件設(shè)置監(jiān)聽功能分析
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)AlertDialog中View的控件設(shè)置監(jiān)聽功能,結(jié)合實(shí)例形式分析了Android針對(duì)AlertDialog中的控件使用View進(jìn)行監(jiān)聽的相關(guān)操作技巧,需要的朋友可以參考下2017-11-11android studio xml文件實(shí)現(xiàn)添加注釋
這篇文章主要介紹了android studio xml文件實(shí)現(xiàn)添加注釋,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android中通過樣式來去除app的頭及界面全屏(備忘)的實(shí)現(xiàn)方法
這篇文章主要介紹了Android中通過樣式來去除app的頭及界面全屏(備忘)的相關(guān)資料,需要的朋友可以參考下2016-12-12Android震動(dòng)與提示音實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android震動(dòng)與提示音實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12Android 帶進(jìn)度條的WebView 示例代碼
本文主要介紹Android WebView,這里提供實(shí)例代碼,和效果圖供大家參考,希望能幫助有需要的小伙伴2016-07-07Android應(yīng)用開發(fā):電話監(jiān)聽和錄音代碼示例
這篇文章主要介紹了Android應(yīng)用開發(fā)中電話監(jiān)聽和電話錄音的代碼實(shí)例,同時(shí)附錄了一個(gè)拍照、錄像的例子,需要的朋友可以參考下2014-04-04Android模擬器中窗口截圖存成文件實(shí)現(xiàn)思路及代碼
Android模擬器內(nèi)容是用OpenGL渲染的,所以用一般的編程截圖(如PrintWindow()等)會(huì)是黑屏。這是因?yàn)楫嫷臇|西放在framebuffer里 接下來介紹如何實(shí)現(xiàn)Android模擬器中窗口截圖存成文件,感興趣的朋友可以了解下哦2013-01-01APP添加CNZZ統(tǒng)計(jì)插件教程 Android版添加phonegap
這篇文章主要介紹了APP添加CNZZ統(tǒng)計(jì)插件教程,Android版添加phonegap,感興趣的小伙伴們可以參考一下2015-12-12