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