Cairo 核心函式庫實作了Array型別。
它和其他程式語言常見的陣列型別很像,但有幾個關鍵差異:
Array型別的尾端,也只能有效率地從前端移除。你可以用ArrayTrait::new函式建立陣列,也可以用array!巨集:
let empty: Array<u32> = ArrayTrait::new();
let one_to_four = array![1, 2, 3, 4];
元素可以用ArrayTrait::append函式加入陣列:
let mut num_array = array![1, 2, 3, 4];
num_array.append(5);
// -> [1, 2, 3, 4, 5]
元素可以用ArrayTrait::pop_front函式從陣列移除:
let mut one_to_four = array![1, 2, 3, 4];
one_to_four.pop_front();
// -> [2, 3, 4]
Cairo 也引進了Span型別,它的作用像是Array的「快照」。
每個Array都可以用ToSpanTrait::span函式轉換成Span:
let one_to_four = array![1, 2, 3, 4];
let one_to_four_span = one_to_four.span();
// -> [1, 2, 3, 4]
把陣列轉換成Span非常有效率,因為Span只是一種資料結構,讓 Cairo 能「檢視」陣列的某個區段,不會以任何方式修改它。
透過把陣列轉換成Span,Cairo 允許你執行更多操作,比直接對Array允許的還多,例如從 span 的前端移除項目。
let one_to_four = array![1, 2, 3, 4];
let mut one_to_four_span = one_to_four.span();
one_to_four_span.pop_back();
// -> [2, 3, 4]
請注意,我們必須用mut關鍵字把one_to_four_span設成可變,才能呼叫pop_back;它會縮短 span 所「檢視」的陣列區段,藉此修改這個 span。
身為一位見習魔術師,Elyse 需要練習一些基本功。
她有一疊牌,想要加以擺弄。
為了讓事情簡單一點,她只使用 1 到 10 的牌。
這疊牌以Array表示,牌堆的底部在陣列的前端,牌堆的頂端在後端。
實作函式insert_top,它會回傳一份牌堆的副本,並將提供的新牌加到牌堆頂端。
let stack = array![5, 9, 7, 1];
insert_top(stack, 8);
// -> [5, 9, 7, 1, 8]
實作函式remove_top_card,它會回傳一份已移除頂端那張牌的牌堆副本。
如果給定的牌堆是空的,就應該回傳原本的牌堆,內容不變。
let stack = array![3, 2, 6, 4, 8];
remove_top_card(stack);
// -> [3, 2, 6, 4]
實作函式insert_bottom,它會回傳一份牌堆的副本,並將提供的新牌加到牌堆底部。
let stack = array![5, 9, 7, 1];
insert_bottom(stack, 8);
// -> [8, 5, 9, 7, 1]
實作函式remove_bottom_card,它會回傳一份已移除底部那張牌的牌堆副本。
如果給定的牌堆是空的,就應該回傳原本的牌堆,內容不變。
let stack = array![8, 5, 9, 7, 1];
remove_bottom_card(stack);
// -> [5, 9, 7, 1]
實作函式check_size_of_stack,用來檢查牌堆的大小是否等於給定的stack_size。
let stack = array![3, 2, 6, 4, 8];
check_size_of_stack(stack, 4);
// -> false
要了解為什麼在 Cairo 中操作陣列不像在其他程式語言裡那麼直接,不妨記住一點:Cairo 採用不可變的記憶體模型,也就是說,記憶體單元一旦被寫入,就永遠無法覆寫,只能讀取。
這個語言在某種程度上把這項特性抽象掉了,讓開發者能像變數是可變的一樣來宣告和使用變數。
雖然這讓寫程式變得稍微困難一些,尤其是使用Array型別的程式(包括底層其實是「位元組陣列」的ByteArray),但它讓你能寫出_可證明_的程式,即使在不受信任的機器上也能放心執行,因此這樣的取捨非常值得。