# 數組
`數組`可以聲明時指定長度,或者是變長的。對`storage`的數組來說,元素類型可以是任意的,類型可以是數組,映射類型,數據結構等。但對于`memory`[datalocation]的數組來說。如果函數是對外可見的,那么函數參數不能是映射類型的數組,只能是支持ABI的類型。
一個類型為T,長度為k的數組,可以聲明為`T[k]`,而一個變長的數組則聲明為`T[]`。<br/>
你還可以聲明一個多維數據,如一個類型為`uint`的數組長度為5的變長數組,可以聲明為`uint[][5] x`。需要留心的是,相比非區塊鏈語言,多維數組的長度聲明是反的。
要訪問第三個動態數據的,第二個元素,使用`x[2][1]`。數組的序號是從0開始的,序號順序與定義相反。
`bytes`和`string`是一種特殊的數組。`bytes`類似`byte[]`,但在外部函數作為參數調用中,會進行壓縮打包,更省空間,所以應該盡量使用`bytes`。`string`類似`bytes`,但不提供長度和按序號的訪問方式。
由于`bytes`與`string`,可以自由轉換,你可以將字符串`s`通過`bytes(s)`轉為一個`bytes`。但需要注意的是通過這種方式訪問到的是UTF-8編碼的碼流,并不是獨立的一個個字符。比如中文編碼是多字節,變長的,所以你訪問到的很有可能只是其中的一個代碼點。
類型為數組的狀態變量,可以標記為`public`類型,從而讓`Solidity`創建一個訪問器,如果要訪問數組的某個元素,指定數字下標就好了。
## 創建一個數組
可使用`new`關鍵字創建一個`memory`的數組。與`stroage`數組不同的是,你不能通過`.length`的長度來修改數組大小屬性。我們來看看下面的例子:
```
pragma solidity ^0.4.0;
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;
}
}
```
在上面的代碼中,`f()`方法嘗試調整數組`a`的長度,編譯器報錯`Error: Expression has to be an lvalue.`。但在`g()`方法中我們看到可以修改<sup id="fnref5">[5](#fn5)</sup>。
## 字面量及內聯數組
數組字面量,是指以表達式方式隱式聲明一個數組,并作為一個數組變量使用的方式。下面是一個簡單的例子:
```
pragma solidity ^0.4.0;
contract C {
function f() {
g([uint(1), 2, 3]);
}
function g(uint[3] _data) {
// ...
}
}
```
通過數組字面量,創建的數組是`memory`的,同時還是定長的。元素類型則是使用剛好能存儲的元素的能用類型,比如代碼里的`[1, 2, 3]`,只需要`uint8`即可存儲。由于`g()`方法的參數需要的是`uint`(默認的`uint`表示的其實是`uint256`),所以要使用`uint(1)`來進行類型轉換。
還需注意的一點是,定長數組,不能與變長數組相互賦值,我們來看下面的代碼:
```
pragma solidity ^0.4.0;
contract C {
function f() {
// The next line creates a type error because uint[3] memory
// cannot be converted to uint[] memory.
uint[] x = [uint(1), 3, 4];
}
```
限制的主要原因是,ABI不能很好的支持數組,已經計劃在未來移除這樣的限制。(當前的ABI接口,不是已經能支持數組了?)
## 數組的屬性和方法
### length屬性
數組有一個`.length`屬性,表示當前的數組長度。`storage`的變長數組,可以通過給`.length`賦值調整數組長度。`memory`的變長數組不支持。
不能通過訪問超出當前數組的長度的方式,來自動實現上面說的這種情況。`memory`數組雖然可以通過參數,靈活指定大小,但一旦創建,大小不可調整,對于變長數組,可以通過參數在編譯期指定數組大小。
### push方法
`storage`的變長數組和`bytes`都有一個`push()`,用于附加新元素到數據末端,返回值為新的長度。
```
pragma solidity ^0.4.0;
contract C {
uint[] u;
bytes b;
function testArryPush() returns (uint){
uint[3] memory a = [uint(1), 2, 3];
u = a;
return u.push(4);
}
function testBytesPush() returns (uint){
b = new bytes(3);
return b.push(4);
}
}
```
### 限制的情況
當前在外部函數中,不能使用多維數組。
另外,基于EVM的限制,不能通過外部函數返回動態的內容。
```
pragma solidity ^0.4.0;
contract C {
function f() returns (uint[]) {
}
}
```
在上面的例子中,通過web.js調用能返回數據,但在Solidity中不能返回數據。一種臨時的解決辦法,是使用一個非常大的靜態數組。
```
pragma solidity ^0.4.0;
contract ArrayContract {
//the orginal length of m_aLotOfIntegers is 2**20
//run it cause a out of gas,so change it to a much smaller 2**2 for test
uint[2**2] m_aLotOfIntegers;
// Note that the following is not a pair of arrays but an array of pairs.
bool[2][] m_pairsOfFlags;
// newPairs is stored in memory - the default for function arguments
function setAllFlagPairs(bool[2][] newPairs) {
// assignment to a storage array replaces the complete array
m_pairsOfFlags = newPairs;
}
function setFlagPair(uint index, bool flagA, bool flagB) {
// access to a non-existing index will throw an exception
m_pairsOfFlags[index][0] = flagA;
m_pairsOfFlags[index][1] = flagB;
}
function changeFlagArraySize(uint newSize) {
// if the new size is smaller, removed array elements will be cleared
m_pairsOfFlags.length = newSize;
}
function clear() {
// these clear the arrays completely
delete m_pairsOfFlags;
delete m_aLotOfIntegers;
// identical effect here
m_pairsOfFlags.length = 0;
}
function addFlag(bool[2] flag) returns (uint) {
return m_pairsOfFlags.push(flag);
}
function createMemoryArray(uint size) {
// Dynamic memory arrays are created using `new`:
bool[2][] memory arrayOfPairs = new bool[2][](size);
m_pairsOfFlags = arrayOfPairs;
}
}
```
更多請查看這里的重新梳理: [http://me.tryblockchain.org/solidity-array.html](http://me.tryblockchain.org/solidity-array.html)
- Solidity語言
- 入門說明
- Solidity智能合約文件結構
- 智能合約源文件的基本要素概覽
- 值類型
- 類型
- 布爾
- 整型
- 地址
- 字節數組
- 小數
- 字符串
- 十六進制字面量
- 枚舉
- 函數
- 引用類型
- 引用類型
- 數據位置
- 數組
- 數據結構
- 雜項
- 映射
- 左值運算符
- 類型間的轉換
- 類型推斷
- 單位
- 貨幣單位
- 時間單位
- 語言內置特性
- 特殊變量及函數
- 數學和加密函數
- 地址相關
- 進階
- 入參和出參
- 控制結構
- 函數調用
- 創建合約實例
- 表達式的執行順序
- 賦值
- 作用范圍和聲明
- 異常
- 內聯匯編
- 合約詳解
- 合約
- 可見性或權限控制
- 訪問函數
- 函數修改器
- 常狀態變量
- 回退函數
- 事件
- 繼承
- 接口
- 其它
- 庫
- 狀態變量的存儲模型
- 內存變量的存局
- 調用數據的布局