簡介
dart中有四種集合,分別是Set,List,Map和queues。這些集合在使用中需要注意些什麼呢?什麼樣的使用才是最好的使用方法呢?一起來看看吧。
使用字面量建立集合
對於常用的Set,Map和List三個集合來說,他們是有自己的無參建構函式的:
factory Set() = LinkedHashSet<E>;
external factory Map();
@Deprecated("Use a list literal, [], or the List.filled constructor instead")
external factory List([int? length]);
可以看到Set和Map是可以使用建構函式的。但是對於List來說,無參的建構函式已經不推薦使用了。
對於Set和Map來說,可以這樣構造:
var studentMap = Map<String, Student>();
var ages = Set<int>();
但是dart官方推薦直接使用字面量來建立這些集合,如下所示:
var studentMap = <String, Student>{};
var ages = <int>{};
為什麼呢?這是因為dart中的字面量集合是非常強大的。可以通過擴充套件運算子,if和for語句對集合進行構造和擴充套件,如下所示:
var studentList = [
...list1,
student1,
...?list2,
for (var name in list3)
if (name.endsWith('jack'))
name.replaceAll('jack', 'mark')
];
不要使用.length來判斷集合是否為空
對應dart的可遍歷集合來說,這些集合並沒有儲存集合的長度資訊,所以如果你呼叫集合的.length方法,可能會導致集合的遍歷,從而影響效能。
注意Set和List是可遍歷的,而Map是不可遍歷的。
所以,我們需要呼叫集合的.isEmpty 和 .isNotEmpty方法來判斷集合是否為空,這樣速度更快。
if (studentList.isEmpty) print('it is empty');
if (studentList.isNotEmpty) print('it is not empty');
可遍歷物件的遍歷
對應Set和List這兩個可遍歷的集合來說,有兩種遍歷方法,可以通過呼叫forEach() 方法或者for-in來進行遍歷,如下所示:
for (final student in studentList) {
...
}
studentList.forEach((student) {
...
});
這兩種方法中,dart推薦使用for in的寫法。
當然,如果你想將現有的function應用在集合中的每個元素中,forEach也是可以的:
studentList.forEach(print);
注意,因為Map是不可遍歷的,所以上面的規則對Map並不適用。
List.from和iterable.toList
可遍歷物件可以通過呼叫toList將其轉換成為List,同樣的List.from也可以將可遍歷物件轉換成為List。
那麼兩者有什麼區別呢?
var list1 = iterable.toList();
var list2 = List.from(iterable);
兩者的區別是iterable.toList並不會改變list中資料的型別,而List.from會. 舉個例子:
// Creates a List<String>:
var studentList = ['jack', 'mark', 'alen'];
// Prints "List<String>":
print(studentList.toList().runtimeType);
// Prints "List<dynamic>":
print(List.from(studentList).runtimeType);
當然,你也可以使用List<T>.from來強制對建立出來的List進行型別轉換。
List<String>.from(studentList)
where和whereType
對於可遍歷物件來說,兩個過濾集合中元素的方法,他們是where和whereType。
比如,我們需要過濾List中的字串,則可以這樣寫:
var studentList = ['jack', 'ma', 18, 31];
var students1 = studentList.where((e) => e is String);
var students2 = studentList.whereType<String>();
看上去兩者沒有太大的區別,都可以得到應有的結果。但是兩者事實上還是有區別的,因為對應where來說,返回的是一個Iterable<Object>
,所以上面的例子中,如果我們真的需要返回String,還需要對返回結果進行case:
var students1 = studentList.where((e) => e is String).cast<String>();;
所以,如果你要返回特定的物件時候,記得使用whereType。
避免使用cast
cast通常用來對集合中的元素進行型別轉換操作,但是cast的效能比較低,所以在萬不得已的情況下,一定要避免使用cast。
那麼如果不使用cast,我們怎麼對型別進行轉換呢?
一個基本的原則就是在構建集合的時候提前進行型別轉換,而不是在構建集合之後再進行整體的cast。
比如下面的例子從一個dynamic型別的List轉換成為int型別的List,那麼我們可以在呼叫List.from方法的時候進行型別轉換:
var stuff = <dynamic>[1, 2];
var ints = List<int>.from(stuff);
如果是map的話,可以這樣操作:
var stuff = <dynamic>[1, 2];
var reciprocals = stuff.map<double>((n) => 1 / n);
比如我們需要構建一個int的List,那麼在建立之初就可以指定List的內部型別,然後再對其新增元素:
List<int> singletonList(int value) {
var list = <int>[];
list.add(value);
return list;
}
總結
以上就是dart中的集合使用最佳實踐。
本文已收錄於 http://www.flydean.com/30-dart-collection/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!