Loading...

智能合约语言 Solidity 教程 – 数组介绍

智能合约语言 Solidity 教程 – 数组介绍

电报联系方式

数组(Arrays)

数组可以根据需要指定长度或者动态变长。对于存储在区块链上的数组,元素类型可以是多样的,包括数组、映射类型、结构体等。但对于在区块链智能合约的内存中使用的数组,在公共函数的参数中,它必须是支持ABI(Application Binary Interface)的类型,因此不支持映射类型的数组。无论数组的长度是固定的还是动态变长的,我们可以使用以下方式声明:

  • 对于一个元素类型为T,长度为k的固定大小数组,我们可以声明为T[k]。
  • 对于动态大小(变长)的数组,我们可以简单地声明为T[]。

还可以声明一个多维数组,如声明一个类型为uint的数组长度为5的变长数组(5个元素都是变长数组),可以声明为uint[][5]。

要访问第三个动态数组的第二个元素,使用x[2][1]。数组的序号是从0开始的,序号顺序与定义相反。

Bytes和字符串可以看作是一种特殊形式的数组。Bytes类似于字节数组(byte[]),但在外部函数调用时,Bytes会自动进行压缩和打包。字符串类似于Bytes,但不允许直接访问元素的长度和索引(目前)。因此,在编写智能合约时,更倾向于使用Bytes而不是字节数组,以便更好地与外部函数进行交互。

创建内存数组

可使用new关键字创建一个memory的数组。与stroage数组不同的是,你不能通过.length的长度来修改数组大小属性。我们来看看下面的例子:

pragma solidity ^0.4.16;

contract C {
function f(uint len) public pure {
uint[] memory a = new uint[](7);

//a.length = 100; // 错误
bytes memory b = new bytes(len);
// Here we have a.length == 7 and b.length == len
a[6] = 8;
}
}

数组常量内联数组

数组常量,是一个数组表达式(还没有赋值到变量)。下面是一个简单的例子:

pragma solidity ^0.4.16;

contract C {
function f() public pure {
g([uint(1), 2, 3]);
}
function g(uint[3] _data) public pure {
// …
}
}

通过数组常量创建的数组是在内存(memory)中存储的,同时也是具有固定长度的。元素的类型被选择为足够容纳数组常量元素的最小类型。举例来说,对于数组常量[1, 2, 3],我们可以选择uint8作为元素类型,这样数组类型就是uint8[3] memory。

然而,在某些情况下,你可能需要将数组中的元素类型进行显式类型转换以满足函数参数的期望类型。例如,如果一个函数的参数期望类型为uint(默认为uint256),你可以使用uint(1)对数组中的第一个元素进行类型转换,以确保数据类型匹配。

还需注意的一点是,定长数组,不能与变长数组相互赋值,我们来看下面的代码:

// 无法编译
pragma solidity ^0.4.0;

contract C {
function f() public {
// The next line creates a type error because uint[3] memory
// cannot be converted to uint[] memory.
uint[] x = [uint(1), 3, 4];
}
}

成员

数组具有一个.length属性,该属性表示当前数组的长度。在存储(storage)中,变长数组可以通过设置.length属性来调整数组的长度。然而,在内存(memory)中,变长数组不支持设置.length属性,这意味着一旦内存数组被创建,其大小是不可调整的。因此,不能通过访问数组长度之外的索引来自动改变数组的大小。虽然内存数组可以在创建时通过参数来指定大小,但一旦创建后,其大小不可更改。

push方法

storage的变长数组和bytes都有一个push方法(string没有),用于附加新元素到数据末端,返回值为新的长度。

限制情况

当前在external函数中,不能使用多维数组。

另外,基于EVM的限制,不能通过外部函数返回动态的内容。

contract C {
function f() returns (uint[]) { … }
}

在这个的例子中,如果通过web.js调用能返回数据,但从Solidity中调用不能返回数据。一种绕过这个问题的办法是使用一个非常大的静态数组。

pragma solidity ^0.4.16;

contract ArrayContract {
uint[2**20] m_aLotOfIntegers;
// 这里不是两个动态数组的数组,而是一个动态数组里,每个元素是长度为二的数组。
bool[2][] m_pairsOfFlags;
// newPairs 存在 memory里,因为是函数参数
function setAllFlagPairs(bool[2][] newPairs) public {
m_pairsOfFlags = newPairs;
}

function setFlagPair(uint index, bool flagA, bool flagB) public {
// 访问不存在的index会抛出异常
m_pairsOfFlags[index][0] = flagA;
m_pairsOfFlags[index][1] = flagB;
}

function changeFlagArraySize(uint newSize) public {
// 如果新size更小, 移除的元素会被销毁
m_pairsOfFlags.length = newSize;
}

function clear() public {
// 销毁
delete m_pairsOfFlags;
delete m_aLotOfIntegers;
// 同销毁一样的效果
m_pairsOfFlags.length = 0;
}

bytes m_byteData;

function byteArrays(bytes data) public {
// byte arrays (“bytes”) are different as they are stored without padding,
// but can be treated identical to “uint8[]”
m_byteData = data;
m_byteData.length += 7;
m_byteData[3] = byte(8);
delete m_byteData[2];
}

function addFlag(bool[2] flag) public returns (uint) {
return m_pairsOfFlags.push(flag);
}

function createMemoryArray(uint size) public pure returns (bytes) {
// Dynamic memory arrays are created using `new`:
uint[2][] memory arrayOfPairs = new uint[2][](size);
// Create a dynamic byte array:
bytes memory b = new bytes(200);
for (uint i = 0; i < b.length; i++)
b[i] = byte(i);
return b;
}
}

开发联系:DEXDAO

 

 

© 版权声明

相关文章

暂无评论

暂无评论...