Dart語法篇之集合的使用與原始碼解析 二

2021-09-29 04:53:04 字數 4803 閱讀 8901

簡述:

我們將繼續dart語法的第二篇集合,雖然集合在第一篇中已經介紹的差不多,但是在這篇文章中將會更加全面介紹有關dart中的集合,因為之前只是介紹了dart:core包中的list、set、map,實際上在dart中還提供乙個非常豐富的dart:collection包, 看過集合原始碼小夥伴都知道dart:core包中的集合實際上是委託到dart:collection包中實現的,所以下面我也會從原始碼的角度去把兩者聯絡起來。當然這裡也只會選擇幾個常用的集合作為介紹。

在dart中的list集合是具有長度的可索引物件集合,它沒有委託dart:collection包中集合實現,完全由內部自己實現。

@patch

class list)

}return result;//否則直接返回相應長度的空集合

} //對應的是list.from建構函式的實現,可將iterable的集合加入到乙個新的集合中,預設growable是true,預設具備擴充套件功能

@patch

factory list.from(iterable elements, )

}return list;

}//如果elements是乙個iterable,就不需要為每個元素做型別測試

//因為在一般情況下,如果elements是iterable,在開始迴圈之前會用單個型別測試替換其中每個元素的型別測試。但是注意下: 等等,我發現下面這段原始碼好像有點問題,難道是我眼神不好,if和else內部執行**一樣。

if (elements is iterable)

//如果是可變長的直接返回這個list即可

if (growable) return list;

//否則呼叫makelistfixedlength使得集合變為定長集合,實際上呼叫native層的c++實現

return makelistfixedlength(list);

} else

if (growable) return list;

return makelistfixedlength(list);

}} //對應的是list.unmodifiable建構函式的實現

@patch

factory list.unmodifiable(iterable elements)

...}

對應的list.fromsdk的原始碼解析

//sdk/lib/_internal/vm/lib/internal_patch.dart中的makelistfixedlength

@patch

listmakelistfixedlength(listgrowablelist)

native "internal_makelistfixedlength";

//runtime/lib/growable_array.cc 中的internal_makelistfixedlength

define_native_entry(internal_makelistfixedlength, 0, 1)

//runtime/vm/object.cc中的array::makefixedlength 返回乙個rawarray

rawarray* array::makefixedlength(const growableobjectarray& growable_array, bool unique)

// 根據傳入list的泛型型別引數,建立乙個新的空的陣列

heap::space space = thread->ismutatorthread() ? heap::knew : heap::kold;//如果是mutatorthread就開闢新的記憶體空間否則復用舊的

array& array = array::handle(zone, array::new(0, space));//建立乙個新的空陣列array

array.settypearguments(type_arguments);//設定拿到的型別引數

return array.raw();//返回乙個相同泛型引數的新陣列

} //如果集合不為空,取出growable_array中的data陣列,且返回乙個帶資料新的陣列array

const array& array = array::handle(zone, growable_array.data());

assert(array.isarray());

array.settypearguments(type_arguments);//設定拿到的型別引數

//這裡主要是**原來的growable_array,陣列長度置為0,內部data陣列置為空陣列

growable_array.setlength(0);

growable_array.setdata(object::empty_array());

//注意: 定長陣列實現的關鍵點來了,會呼叫truncate方法將array截斷used_len長度

array.truncate(used_len);

return array.raw();//最後返回array.raw()

}

總結一下list.from的原始碼實現,首先傳入elements的iterate, 如果elements不帶泛型引數,也就是所謂的原生集合型別,並且是非unique,直接返回空陣列; 如果帶泛型引數空集合,那麼會建立新的空集合並帶上原來泛型引數返回;如果是帶泛型引數非空集合,會取出其中data陣列,來建立乙個新的複製原來資料的集合並帶上原來泛型引數返回,最後需要截斷把陣列截斷成原始陣列長度。

關鍵就是在於它能實現宣告和實現分離,這樣就能復用同一套對外api的宣告,然後對應多套多平台的實現,如果對原始碼感興趣的小夥伴就會發現相同api宣告在js中也有另一套實現,這樣不管是dart for web 還是dart for vm對於上層開發而言都是一套api,對於上層開發者是透明的。

dart:core包中的set集合實際上是委託到dart:collection中的linkedhashset來實現的。集合set和列表list的區別在於集合中的元素是不能重複的。所以新增重複的元素時會返回false,表示新增不成功.

dart:core包中的map集合實際上是委託到dart:collection中的linkedhashmap來實現的。集合map和kotlin類似,key-value形式儲存,並且map物件的中key是不能重複的

queue佇列顧名思義先進先出的一種資料結構,在dart對佇列也做了一定的支援, 實際上queue的實現是委託給listqueue來實現。 queue繼承於efficientlengthiterable介面,然後efficientlengthiterable介面又繼承了iterable.所以意味著queue可以向list那樣使用豐富的操作函式。並且由queue派生出了doublelinkedqueuelistqueue

在dart中linkedlist比較特殊,它不是乙個帶泛型集合,因為它泛型型別上界是linkedlistentry, 內部的資料結構實現是乙個雙鏈表,鍊錶的結點是linkedlistentry的子類,且內部維護了_next_previous指標。此外它並沒有實現list介面

在dart中還有乙個splaytreemap,它的初始化、常用的函式和遍歷方式和linkedhashmap、hashmap使用類似。但是map、hashmap、linkedhashmap、splaytreemap有什麼區別呢。

通過上述各個集合原始碼可以看到,基本上每個集合(list、set、linkedhashset、linkedhashmap、map、hashmap等)中都有from和of命名建構函式。可能有的人有疑問了,它們有什麼區別,各自的應用場景呢。其實答案從原始碼中就看出一點了。以list,map中的from和of為例。

main() ;

var frommap = map.from(map); //返回型別是mapvar ofmap = map.of(map); //返回型別是mapvar list = [1, 2, 3, 4];

var fromlist = list.from(list); //返回型別是listvar oflist = list.of(list); //返回型別是list}

從上述例子可以看出list、map中的from函式返回對應的集合泛型型別是listmap而of函式返回對應集合泛型型別實際型別是listmap。我們都知道dynamic是一種無法確定的型別,在編譯期不檢查型別,只在執行器檢查型別,而具體型別是在編譯期檢查型別。而且從原始碼中可以看到 from函式往往會處理比較複雜邏輯比如需要重新遍歷傳入的集合然後把元素加入到新的集合中,而of函式只需要建立乙個新的物件通過addall函式批量新增傳入的集合元素。

所以這裡為了**效率考慮給出建議是:如果你傳入的原有集合元素型別是確定的,請盡量使用of函式建立新的集合,否則就可以考慮使用from函式。

掌握 Dart 集合的使用

我們將繼續 dart 語法的集合,雖然集合在第一篇中已經介紹的差不多,但是在這篇文章中將會更加全面介紹有關 dart 中的集合,因為之前只是介紹了 dart core 包中的 list set map,實際上在 dart 中還提供乙個非常豐富的 dart collection 包,接下來將會一一介紹...

Dart的基本語法之函式和操作符

操作符1.有參匿名 var func1 name print 2.無參匿名 var func2 print 無參 void main 呼叫時引數順序可選 intadd int a,呼叫時引數順序固定 intadd2 int a,int b 1,c 2 list付預設值需要const修飾 intadd...

python之集合的使用

集合,其實它和列表差不多,只不過它沒有重複的值,而在列表中是可以有相 同的值的,而集合是不允許的,如果你執行下面 就會發現,b把相同的去除 了,集合也是用 括起來的,可是它和字典不同,它沒有key,如下b就是乙個集合 1 2 3 b set 1,3,5,8,5,7,9 print b print t...