前言
在solidity中,数组分为两大类,一类是字节数组,一类是普通数组。 这与java不同,java中无论是字节还是其它数据类型的数组,都是一个分类,只有固定长度和动态长度的区别。 而在solidity中字节数组下面又分为固定长度字节数组和动态长度字节数组。普通数组下面也有分为动态数组和固定数组。 其中,字节数组和string字符串类型常常结合到一起应用。
一.字节数组与字符串
一.固定长度字节数组
在学习solidity的固定长度数组之前,首先需要明白的一点是,字节是用16进制表示的。
在16进制所表示的字节规则中,两个数字/字母占一个字节。 如 aa 所占的16进制字节数组长度为1。 b7ab 所占的16进制字节数组长度为2. f9a8b7b9c521 所占的16进制字节数组长度为6.
变量类型的bytes1和bytes2等等是代表定义固定长度的字节数组。 其后面的数字代表了固定的长度,如bytes1 则代表固定的数组长度为1 ,bytes10 则代表固定的数组长度为10 .
需要注意的是,在solidity中,在为其字节类型的变量赋值时,值前面必须要加上’0x '才可以,否则编译失败。 而且,长度的计算标准,也是忽略了’0x’。
而string字符串等数据,可以转换为16进制(也就是字节)来进行变量值的赋值和定义。
而在智能合约中,经常会出现用字节数组代替字符串 去声明变量值的用法。
pragma solidity ^0.4.16;
contract bytesArray {
bytes1 public length1 = 0xaa;
bytes2 public length2 = 0xb7ab;
bytes6 public length6 = 0xf9a8b7b9c521;
bytes11 public length10 = 0x68656c6c6f20776f726c64;
}
附上两个页面: 1,在线进制转换: https://tool.oschina.net/hexconvert
2,字符串与16进制转换:http://tools.bugscaner.com/text/zifuchuanzhuanhex.html
二. 动态长度字节数组
所谓动态长度字节数组,是指长度可以改变的数组。 比如我一开始定义一个数组的长度为3,但是后来我可以把它的长度改为5.
pragma solidity ^0.4.16;
contract bytesDynamicArray {
bytes dynamicArray = new bytes(3);
function getDynamicArrayLength() view returns(uint){
return dynamicArray.length;
}
function setDynamicArrayData() {
dynamicArray[0] = 0xa7;
dynamicArray[1] = 0xbf;
dynamicArray[2] = 0xdd;
}
function getDynamicArrayData() view returns(bytes) {
return dynamicArray;
}
function setDynamicArrayLength5(){
dynamicArray.length = 5;
}
}
上面的代码中,我们可以看到,我们先是声明了一个长度为3的字节数组成员变量对象(也就是动态字节数组),然后我们按方法顺序从上到下去执行,会充分了解到solidity的动态长度数组有哪些特性。 首先我们调用获取长度函数(getDynamicArrayLength),得到了结果3. 接着我们调用设置字节数组数据的函数(setDynamicArrayData),对数组的设置三个元素数据, 然后我们调用获取字节数组数据的函数(getDynamicArrayData),得到内容’0xa7bfdd’。 接下来,我们再运行设置数组长度的函数(setDynamicArrayLength5),把长度由原先的3设置为5. 那么问题来了,设置为5后就多来了两个数组元素,那么他们的内容是什么呢?我们设置后再运行获取数组数据的函数(getDynamicArrayData),会发现输出的内容是’0xaabfdd0000 ’,至此,我们得出了一个结论,当我们增加一个动态字节数组的长度时,新增加的长度元素内容,是用00来表示一个元素的。
四.字符串
字符串是啥就不说了。 但是有一点需要注意,在solidity中,如果你想取字符串中的某个字符,需要先将该字符串转为字节数组对象,然后再去根据字节数组索引去取才行。
pragma solidity ^0.4.16;
contract stringTest {
string stringStr = "hello!world";
function getStringLength() view returns(uint){
return bytes(stringStr).length;
}
function getStringAll() view returns(string){
return stringStr;
}
function getStringByIndex(uint index) view returns(bytes1){
return bytes(stringStr)[index];
}
}
五.固定长度字节数组转动态长度字节数组
在solidity中,没有办法能够直接将固定长度字节数组转为动态字节数组,所以只能通过for循环来实现。
小知识:memory(引用类型)关键字
我们for循环时要对动态长度字节数组的变量进行赋值,这需要我们使用‘memory’关键字将其手动声明为引用类型才可以。 而在java中是不需要这么做的,但在solidity中,我们要用到引用类型变量时,必须要加上’memory’才行。 与’memory’关键字相关的,则是’storage’关键字,代表指针。 参考:https://www.jianshu.com/p/874558b62572
代码如下:
pragma solidity ^0.4.16;
contract bytesFixedArrayOnBytesDynamicArray {
bytes10 bytesVariable = 0x69206c6f766520796f75;
function getBytesVariable() public view returns(bytes10){
return bytesVariable;
}
function getBytesForDynamicArray() public view returns(bytes){
bytes memory dynamicArrayBytes = new bytes(bytesVariable.length);
for(uint i = 0; i < bytesVariable.length;i++){
dynamicArrayBytes[i] = bytesVariable[i];
}
return dynamicArrayBytes;
}
}
六.动态长度字节数组转String
动态长度字节数组转字符串相对来讲很简单, string(动态字节数组对象) 即可。
pragma solidity ^0.4.16;
contract bytesDynamicArrayForString {
bytes dynamicBytesArray = new bytes(3);
function dataOfStringType() public view returns(string) {
dynamicBytesArray[0] = 0x1d;
dynamicBytesArray[1] = 0xcd;
dynamicBytesArray[2] = 0x7d;
return string(dynamicBytesArray);
}
}
七.固定长度字节数组转String
在此前,固定长度字节数组转动态数组的话,是不能直接转的,只能通过for循环来实现,同样的,固定长度字节数组转string也是需要通过for循环来实现。 我们需要通过for循环,将固定长度字节数组转为动态字节数组,然后再将动态字节数组直接转为string对象。
pragma solidity ^0.4.16;
contract bytesFixedArrayForString {
bytes10 public fixedBytesArray = 0x69206c6f766520796f75;
function getStringOfFixedBytesArray() public view returns(string){
bytes memory bytesDynamicArray = new bytes(fixedBytesArray.length);
for(uint i = 0;i < bytesDynamicArray.length;i++){
bytesDynamicArray[i] = fixedBytesArray[i];
}
string memory str = string(bytesDynamicArray);
return str;
}
}
二.普通数组
普通数组,就是非字节类型的数组,用法和java大致相似,不多叙述了。
一.固定长度数组
定义格式:数据类型[长度] 变量名; 例如:uint[5] arrayA;
pragma solidity ^0.4.16;
contract ordinaryArray {
uint[5] arrayA = [12,2,86,21,3];
uint[5] arrayB;
uint[5] arrayC;
function getArrayA() public view returns(uint[5]){
return arrayA;
}
function getArrayB() public view returns(uint[5]){
arrayB[0] = 1;
arrayB[1] = 3;
arrayB[2] = 5;
arrayB[3] = 7;
arrayB[4] = 9;
return arrayB;
}
function getArrayC() public view returns(uint[5]){
arrayC[0] = 6;
arrayC[1] = 8;
return arrayC;
}
}
二.动态长度数组
定义格式:数据类型[] 变量名; 例如:uint[] arrayB;
pragma solidity ^0.4.16;
contract dynamicArray {
uint[] arrayA = [1,3,5,7,9];
uint[] arrayB;
function setLengthAndGetDataOfArrayA() public view returns(uint[]){
arrayA.length = 8;
arrayA[5] = 212;
arrayA[6] = 712;
arrayA[7] = 612;
return arrayA;
}
function setLengthAndGetDateOfArrayB() public view returns(uint[]){
arrayB.length = 2;
arrayB[0] = 6;
arrayB[1] = 2;
arrayB.push(1212);
return arrayB;
}
}
三.固定二维数组
格式:数据类型[二维数组长度][一维数组长度] 变量名; 例如:uint[2][5] uintDimensionArray;
pragma solidity ^0.4.16;
contract ordinaryDimensionArray {
uint[2][5] uintDimensionArray = [[11,22],[22,11],[33,44],[44,33],[55,77]];
function getUintDimensionArrayLength() public view returns(uint){
return uintDimensionArray.length;
}
function getUintDimensionArrayAll() public view returns(uint[2][5]){
return uintDimensionArray;
}
function getUintDimensionArrayByIndex() public view returns(uint[2]){
return uintDimensionArray[3];
}
function setAndGetUintDimensionArrayByIndex() public view returns(uint[2]){
uintDimensionArray[1] = [222,111];
return uintDimensionArray[1];
}
}
四.动态二维数组
格式:数据类型[][] 变量名; 例如:string[][] strArray;
动态二维数组和固定二维数组不同的是,动态二维数组不支持直接获取所有元素内容,只能获取单个索引的元素内容。
pragma solidity ^0.4.16;
contract dynamicDimensionArray {
string[][] strArray = [["hello","world!"],["hi","solidity!"]];
uint[][] uintArray = [[11,22],[33,44]];
function getStrArrayByIndex() public view returns(string){
return strArray[0][1];
}
function addElementAndGetStrArrayByIndex() public view returns(string){
strArray.push(["你好","同学"]);
return strArray[2][0];
}
function getUintArrayLength() public view returns(uint){
return uintArray.length;
}
function getUintArrayByIndex() public view returns(uint[]){
return uintArray[0];
}
function addElementAndGetUintArrayByIndex() public view returns(uint[]){
uintArray.push([1233,3214]);
return uintArray[2];
}
}
三.数组字面(直接创建并返回)
说到‘数组字面’可能你不理解这是什么,但如果用java代码来表示,你应该就明白了。 比如,在java中,我直接 return new String {"你好"}; 代表着直接返回一个动态数组对象给调用处。 那么solidity中的‘数组字面’概念就是指这个,此处我以普通固定长度数组来做例子。
注意点: 不过需要注意的,返回值处,对于所要返回类型的位数(如uint等类型的话,则可分为16位或256位等),要和其真实返回的位数相匹配,不然会编译出错。 对于这种问题,有两个办法解决: 1.在returns的括号内,对类型的位数进行定义,例如: function getUintFor8bit() public view returns(uint16 [3]) 2.retruns不再指定位数,在return处,对其位数进行强转,例如: return [uint( 257) ,2,3];
pragma solidity ^0.4.16;
contract returnArray {
function getUintFor8bit() public view returns(uint8[3]){
return [251,32,3];
}
function getUintFor256bit() public view returns(uint16[3]){
return [256,32,3];
}
function getUintForTypeReturn() public view returns(uint[3]){
return [uint(257),2,3];
}
}
|