Solidity基礎入門知識(四)列舉、儲存型別和陣列
今天米切爾致敬卡特轉身成功問鼎扣籃王,可惜只有形而無神,就連形都差點意思--!
列舉型別:一個變數可能的取值都知道,就可以把它定義為列舉型,然後把變數的值一一列出來,令變數的值只限於列舉出來的值的範圍內。例如月份、星期幾、天氣等情況,列舉型別用enum關鍵字來定義。
例子:enum weekday{sun,mon,tue,wed,the,fri,sat};
上面聲明瞭一個列舉型別weekday,花括號中的sun mon等稱為列舉元素,weekday的值只能是括號內的七個值。
在程式中可以用weekday.sun這種格式來引用列舉型別的值。列舉元素的值在沒有指定的情況下,第一個預設為0,往後的自增一,例如sun=0,mon=1,tue=2。有指定值的時候就用指定值,其後元素如果沒有指定則自增一。
資料位置(儲存型別):複雜型別,如陣列(arrays)
和資料結構(struct)
在Solidity中有一個額外的屬性,資料的儲存位置,等同於資料的儲存方式,臨時還是永久。可選為memory(臨時)
和storage(永久)
。
memory
儲存位置同我們普通程式的記憶體一致。即分配,即使用,越過作用域即不可被訪問,等待被回收。而在區塊鏈上,由於底層實現了圖靈完備,故而會有非常多的狀態需要永久記錄下來。比如,參與眾籌的所有參與者,參與投票的所有人員。那麼我們就要使用storage
這種型別了,一旦使用這個型別,資料將永遠存在。
基於程式的上下文,大多數時候這樣的選擇是預設的,我們可以通過指定關鍵字storage
和memory
修改它。
預設的函式引數,包括返回的引數,他們是memory
。預設的區域性變數是storage
的。而預設的狀態變數(合約宣告的公有變數)是storage
。
另外還有第三個儲存位置calldata
。它儲存的是函式引數,是隻讀的,不會永久儲存的一個數據位置。外部函式的引數(不包括返回引數)被強制指定為calldata
。效果與memory
差不多。
資料位置指定非常重要,因為不同資料位置變數賦值產生的結果也不同。在memory
和storage
之間,以及它們和狀態變數
(即便從另一個狀態變數)中相互賦值,總是會建立一個完全不相關的拷貝。(這句話沒看懂,再議!)
將一個storage
的狀態變數,賦值給一個storage
memory
的引用型別賦值給另一個memory
的引用,不會建立另一個拷貝。(再議,——!)
陣列(arrays):一個型別為uint,元素個數為5的陣列x應該這樣定義:uint[5] x,而一個元素個數可變的陣列應該定義為:uint[ ] x。定義多維陣列:uint [5][4] x,表示二維陣列x包含四個陣列,每個陣列有五個元素。uint[ ][4],表示包含四個陣列,每個數組裡的元素個數可變。需要注意的是,相比python等語言,多維陣列的元素個數宣告是相反的。x[2][1],這個表示訪問第三個數組裡的第二個元素,這裡的順序是正常順序(--!)。
型別為陣列的狀態變數,可以標記為public(公共)型別,從而讓solidity建立一個訪問器(再議)。
陣列有一個length屬性,表示當前的陣列長度(即一維陣列的元素數量,二維數組裡一維陣列的數量)。storage型別的變長陣列可以通過給length賦值來改變陣列的長度,但memory型別(例如用new關鍵字建立的陣列)的陣列不支援這個功能,但可以通過調整引數的方法來改變長度。
例子:
contract C {
function f() {
//建立一個memory的陣列
uint[] memory a = new uint[](7);
//不能修改長度
//Error: Expression has to be an lvalue.
//a.length = 100;
}
//storage
uint[] b;
function g(){
b = new uint[](7);
//可以修改storage的陣列
b.length = 10;
b[9] = 100;
}
}
可以看出來,storage型別的可以通過賦值length來更改長度,但memory型別的不行。
push方法:storage的變長陣列和bytes陣列都有一個push方法,用於新增新元素到陣列末端,返回值為新的長度。
例子:a=[1,2,3] a.push(4)意為將元素4新增到陣列a中,新的a為[1,2,3,4],並返回陣列a的新長度。