3.10 solidity資料結構詳解

尹成發表於2018-11-08

1. Solidity資料結構:陣列、列舉、對映/字典、結構體

        a. 列舉型別(Enums)

            i. 列舉型別是在Solidity中的一種使用者自定義型別。他可以顯示的轉換與整數進行轉換,但不能進行隱式轉換。顯示的轉換會在執行時檢查數值範圍,如果不匹配,將會引起異常。列舉型別應至少有一名成員。

            ii. 與其它程式語言一樣、列舉型別預設從0開始

        b. 位元組陣列(fixed byte arrays)

            i. 定長位元組陣列:byte1,……,byte32,允許值以步長1遞增,預設byte為byte1

                1. 運算子:

                    a. 比較:<=,<,==,!=,>=和>

                    b. 位運算子:&,|,(^異或),(~非)

                2. 支援下標訪問,取值[0,n),n表示長度

                3. .length:表示這個位元組陣列的長度---只讀(長度不可變)

                4. 內部位元組不可變

            ii. 動態位元組陣列:

                1. Bytes:動態長度的位元組陣列,參見陣列(Arrays)。非值型別

                2. String:動態長度的UTF-8編碼的字元型別,參見陣列(Arrays)。非值型別

                3. 使用原則:

                    a. 如果想要儲存UTF-8的字串資料,使用string,如果想要儲存任意長度的位元組資料,使用bytes

                    b. 如果長度確定,儘量使用byte1-byte32中的一個,可以節省空間

        c. 陣列

            i. 陣列可以宣告時指定長度,或者是變長的。對storage的陣列來說,元素型別可以是任意的,型別可以是陣列,對映型別,資料結構等。但對於memory的陣列來說。如果函式是對外可見的,那麼函式引數不能是對映型別的陣列,只能是支援ABI的型別

            ii. 宣告方式

                1. 定長:T[K]

                2. 不定長:T[]

                3. 二維陣列:uint [][5]x

                    a. 注意,在solidity中,多給陣列的行列位置和大多數程式語言是相反的

                        i. uint[3][5]x代表陣列X是5行3列

                        ii. Uint[][5]x代表陣列X有5行,每一行的列是一個動態陣列

            iii. 型別為陣列的狀態變數,可以標記為public型別,從而讓Solidity建立一個訪問器,如果要訪問陣列的某個元素,指定數字下標就好了。

            iv. 建立陣列:可使用new關鍵字建立一個memory的陣列。與stroage陣列不同的是,你不能通過.length的長度來修改陣列大小屬性。

            v. 字面量及內聯陣列

            vi. 陣列字面量,是指以表示式方式隱式宣告一個陣列,並作為一個陣列變數使用的方式。

                1. 通過陣列字面量,建立的陣列是memory的,同時還是定長的。元素型別則是使用剛好能儲存的元素的能用型別。

                2. 定長陣列,不能與變長陣列相互賦值。

            vii. 陣列的屬性和方法

                1. 陣列有一個.length屬性,表示當前的陣列長度。storage的變長陣列,可以通過給.length賦值調整陣列長度。memory的變長陣列不支援。

                2. push方法,storage的變長陣列和bytes都有一個push(),用於附加新元素到資料末端,返回值為新的長度。

        d. 對映

            i. 對映或字典型別,一種鍵值對的對映關係儲存結構。定義方式為mapping(_KeyType => _KeyValue)。鍵的型別允許除對映,動態陣列,合約,列舉,結構體之外的所有型別,值的型別無限制。

            ii. 對映可以被視作為一個雜湊表,其中所有可能的鍵已被虛擬化的建立,被對映到一個預設值(二進位制表示的零)。但在對映表中,我們並不儲存鍵的資料,僅僅儲存它的keccak256雜湊值,用來查詢值時使用。所以說 對映沒有長度,鍵集合(或列表),值集合(或列表)這樣的概念。

            iii. solidity中,字典無法迭代(考慮自己實現)

        e. 結構體

            i. 結構體是solidity中的自定義資料型別,其中可以包含字串,整形等基本的資料型別,以及陣列,對映,結構全等複雜的型別

    2. Solidity地址與對映、全域性單位、轉賬

        a. 地址(Address)

            i. 地址型別是solidity專有的型別,它代表以太坊地址的長度,大小20個位元組,160位,所以可以用一個uint160編碼。地址是所有合約的基礎,所有的合約都會繼承地址物件,也可以隨時將一個地址串,得到對應的程式碼進行呼叫。當然地址代表一個普通帳戶時,就沒有這些功能了。

            ii. 從版本0.5.0開始,合約不再是從地址型別派生的,但仍可以顯式轉換為地址。

            iii. 支援的運算子:<=,<,==,!=,>=和>

            iv. 成員

                1. 屬性:

                    a. balance,通過balance屬性可以得到一個地址的餘額、如果是想要得到當前地址的餘額,可以直接通過this進行呼叫:this.balance,address(this).balance。

                    b. Transfer,從合約發起方傳送定量的wei到給定的地址,如果丟擲失敗,補助2300GAS,GAS補助不可調節

                2. 函式

                    a. Send():從合約發起方向某個地址傳送貨幣(單位是wei 一個eth等於10^18wei),如果丟擲失敗,補助2300GAS,GAS補助不可調節

                        i. 注意:在以前我們通常使用this.address的方式來獲取當前合約地址,但是,隨著solidity的改進,現在通常使用address(this)的方式。

                    b. Call()、Delegatecall()、Callcode():都是底層的訊息傳遞呼叫,除非不得已,否則不建議使用,因為呼叫這三個合約,意味著有可能會把你合約的控制權交給對方。

        b. 全域性變數

            i. 全域性變數可以在合約指令碼中的任何地方使用

            ii. solidity內建的全域性變數:

                This    合約地址的引用

                This.balance    餘額

                This.someFunction() 通過外部方式呼叫函式

                Msg.sender  傳送者的地址

                Msg.value   傳送給合約的以太幣數量,單位為wei

                Msg.data    bytes,完整的呼叫資料

                Msg.gas 剩餘gas

                Tx.origin   交易傳送者的地址

                Tx.gasprice gas的價格

                Now 當前時間=block.timestamp

                Block.number    當前區塊號

                Block.difficulty    當前區塊難度

                Block.blockhash(1)  給定區塊號的hash值(byte32),只支援最近的256個區塊

                Block.coinbase  當前區塊的礦工地址

                Block.gasLimit();   當前區塊的gaslimit

                Block.timestamp 當前區塊的時間戳

    3. Solidity控制語句

        a. Solidity中支援if-else, while, do-while,for,break,continue,return,?:(三目運算)

    4. Solidity物件導向程式設計

        a. 物件導向程式設計:物件導向的概念是針對於程式導向而言的、也是我們常說的OO程式設計,它一種對現實世界理解和抽象的方法。最初的物件導向專指在程式中採用"封裝","繼承","多型"的設計方法,發展到今天,物件導向的概念和應用已超越了程式設計和軟體開發

        b. solidity的物件導向

            i. 繼承:

                1. 什麼是繼承:繼承就是類與類之間一種特殊與一般的關係

                2. 通過"is"關鍵字來繼承另一個合約。派生合約可以訪問父類合約所有的非private型別的變數,包括內部函式和狀態變數,但不能通過"this"呼叫

                3. 繼承支援傳遞引數

                4. 多重繼承:solidity允許多重繼承,但在多重繼承中不能出現重名合約。當一個合約從多個其它合約那裡繼承,在區塊鏈上僅會建立一個合約,在父合約裡的程式碼會複製來形成繼承合約(也就是將父類的程式碼拷貝到子類中)。

            ii. 抽象

                1. 抽象函式是沒有函式體的的函式,這樣的合約不能通過編譯,即使合約內也包含一些正常的函式。但它們可以做為基合約被繼承。

            iii. 介面(interface)

                1. 介面與抽象合約類似,與之不同的是,介面內沒有任何函式是已實現的,它有如下限制:

                    a. 不能繼承其它合約,或介面

                    b. 不能定義建構函式

                    c. 不能定義變數

                    d. 不能定義結構體

                    e. 不能定義列舉

                2. 如果我們的合約需要和區塊鏈上的其它合約對話,則需要先定義一個介面

            iv. 庫

                1. 庫是一種不同型別的合約,沒有儲存,不擁有以太幣。

                2. 沒有payable,沒有fallback函式

            v. Import

                1. 概念:匯入其它原始檔

                2. 語法

                    a. Import "filename":從filename中匯入所有的全域性symbols到當前全域性範圍

                    b. Import * as symbolName from "filename":建立新的全域性symbol symbolName,其成員都是來自“filename”的全域性symbols

                    c. Import {symbol1 as alias,symbol2} from "filename":建立新的全域性symbols“alias”和“symbol2”,它將分別從”filename” 引入symbol1 和 symbol2

                    d. import "filename" as symbolName 等價於 Import * as symbolName from "filename"

 

相關文章