二维数组

在几何的世界里,一维为线,二维为面;而在程序的的世界中,一维为列表,二维为表;

通学智能合约系列(十)--二维数组_二维数组

类似于上图,我们就可以看做是一个表结构,我们可以用行和列来确定其中的元素,那么在solidity中怎么表示呢?

pragma solidity ^0.4.16;

contract TwoArray{

uint[2][3] arr = [[1,2],[23,4],[6,7]];

function getLength() view returns(uint){
return arr.length;
}

}

上面我们演示了二维数组获取长度的方式,也就是我们上图的二维数组中有3个元素。也就是说,二维数组中存放的元素是一维数组。想要获取具体元素的信息,我们就可以将二维数组进行遍历,得到一维数组,再进行一次一维数组遍历,就可以获取到我们具体的元素内容了。下面我们来看代码:

function getContentLegth() view  returns(uint){
return arr[0].length;
}

通学智能合约系列(十)--二维数组_区块链_02

相信有编程基础的同学不用我在过多解释了,如果是初学者的话,可以记住这个表示方式,和我们其他编程语言类似,但稍稍会有点差别。可以按照行列表达式的方式去理解他,一行代表一个一维数组,列的个数代表有多少个一维数组。

在者,我们看看固定长度二维数组是否可以改变其长度呢?


显然,从名字就可以断出是不可以进行修改的。

接下来,我们看一看数组的内容输出的结果以及遍历。

function getContent() view  returns(uint[2][3]){
return arr;
}

通学智能合约系列(十)--二维数组_二维数组_03

从上图可以看出,我们的二维数组输出是线性表示的。那么现在假设我们要对二维数组内所有内容进行累加求和。

就需要对二维数组进行遍历,那么上代码

function add() view returns(uint){
uint sum = 0;
for(uint i = 0;i<arr.length;i++){
for(uint j=0;j<arr[0].length;j++){
sum += arr[i][j];
}
}
return sum;
}

通学智能合约系列(十)--二维数组_区块链_04

从上图中可以看出,结果符合我们的预期,然后再回头看代码,值得注意的是​​j<arr[0].length;​​因为我们这个是固定长度的二维数组,二维数组中每一个元素的个数是相等的,所以可以这么写。

大家可以看,下面这种增加元素或者减少元素的写法都是编译报错的。

通学智能合约系列(十)--二维数组_区块链_05

最后,介绍一下我们可以直接修改二维数组的内容。

function changeContent(){
arr[1][0] = 3;
}

通学智能合约系列(十)--二维数组_一维数组_06

大家可以发现,我们可以这样直接地修改数组,得到我们预期的结果,值得注意的一点是,​​数组的下标都是从0开始的​​。

在这里,我们固定长度的二维数组也就介绍完啦。下节,我们看看可变长度二维数组。

可变长度二维数组

和以前的之前的数组类似,固定长度二维数组和可变长度二维数组也存在一些异同点,下面我们仅仅介绍不一样的地方。

差异1:可变长度二维数组不支持直接获取数组内容


差异2:可变长度二维数组支持修改其长度

pragma solidity ^0.4.16;

contract DynamicTwoArray{

uint[][] arr = [[1,2],[3,4],[6,7]];

// function getContent() view returns(uint[][]){
// return arr;
// }

function changeLength() {
arr.length = 10;
}

function getLength() view returns(uint) {
return arr.length;
}

function getContntLength() view returns(uint) {
return arr[0].length;
}

}

这里我写了两个函数,一个是获取二维数组的长度,一个是获取数组内容的长度,会发现,我们修改的只是二维数组的长度,并没有改变掉二维数组中一维数组的长度。

通学智能合约系列(十)--二维数组_二维数组_07

另外要说明的一点是,可变长二维数组初始化的时候也是不允许每个一维数组长度不相同的。

通学智能合约系列(十)--二维数组_数组_08

数组字面量

前面我们介绍过字节数组的字面量,这里也说说数组字面量。

首先,我们先来看一个例子:

pragma solidity ^0.4.16;

contract ArrayLiterals{

function getArrayLiterals() returns(uint[3]){
return [1,2,3];
}

function getArrayLiterals2() returns(uint[3]){
return [256,2,3];
}

}


在这里,我们相当于再复习一下字节数组uint类型的知识。我们具体来看看他的报错信息。

browser/Math.sol:6:15: TypeError: Return argument type uint8[3] memory is not implicitly convertible to expected type (type of first return variable) uint256[3] memory.
return [1,2,3];
^-----^
browser/Math.sol:10:15: TypeError: Return argument type uint16[3] memory is not implicitly convertible to expected type (type of first return variable) uint256[3] memory.
return [256,2,3];
^-------^

我们查看错误信息会发现,第一个我们返回的数组元素​​1,2,3​​​,都是​​uint8类型的​​​,因为1,2,3 都只占用1个字节,也就是8位。而uint[3]相当于uint[256]3,因为uint默认是256位的。第二个我们返回的数组元素​​256,2,3​​​,其中256是16位(因为我们知道255是8位的最大十进制数,所以256占两个字节,16位)而剩下的都是​​uint8类型的​​,而uint[3]相当于uint[256]3,因为uint默认是256位的。

所以知道了以上规则后,你们觉得怎么修改好呢~?

显然,修改返回值字面量是不现实的,那么我们就可以在返回值定义参数上下功夫,例如第二个,我们可以这么改。

pragma solidity ^0.4.16;

contract ArrayLiterals{

// function getArrayLiterals() returns(uint[3]){
// return [1,2,3];
// }

function getArrayLiterals2() view returns(uint16[3]){
return [256,2,3];
}

}

对,将返回值参数中的类型改为数组元素中最大值的类型即可。

通学智能合约系列(十)--二维数组_二维数组_09

当然 上面的第一个例子也可以将函数返回参数的类型改为uint8[3]吗?不过还有一种方式可以,下面请看

function getArrayLiteterrals5() view returns(uint[3]){
return [uint(1),2,3];
}

是的,我们可以通过这种强的方式也可以达到我们的目的。

那么我们清楚了数组字面量有什么用呢?因为在实际的应用当中,我们的合约大多数形式就是通过数组来传参的,例如我们要对一个数据进行就和,我们可以这么做。

function getArrrayLiteralalss6(uint[3] arr) view returns(uint){
uint sum = 0;
for(uint i= 0;i<arr.length;i++){
sum += arr[i];
}
return sum;
}

通学智能合约系列(十)--二维数组_一维数组_10

而我们实际的入参就是我们的数组字面量啦。如是​​[100,200,300]​​;

好了,到这里,我们关于数组的内容,就介绍完毕啦,我们简单做一个回顾,我们介绍了字节数组、数组、二维数组。而围绕数组的内容主要是关于数组的初始化、获取长度及其内容,修改长度及其内容。还有类型化,只要大家跟着码上一遍,相信也能够很快地掌握这些内容。