在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 {
// 字节数组长度1,超过则报错 ‘aa'占长度1.
bytes1 public length1 = 0xaa; // (二进制)10101010 --> aa
//字节数组长度2,超过则报错 ‘b7ab'占长度2.
bytes2 public length2 = 0xb7ab;//(二进制) 1011011110101011 --> b7ab
//字节数组长度6,超过则报错 ‘f9a8b7b9c521'占长度6.
bytes6 public length6 = 0xf9a8b7b9c521;//(二进制) 111110011010100010110111101110011100010100100001 --> f9a8b7b9c521
//字节数组长度11,超过则报错 ’68656c6c6f20776f726c64‘占长度11
bytes11 public length10 = 0x68656c6c6f20776f726c64;// (字符串) hello world --> 68656c6c6f20776f726c64
}
附上两个页面:
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);// 定义一个长度为3的动态字节数组成员对象。
//获取长度
function getDynamicArrayLength() view returns(uint){
return dynamicArray.length;
}
//设置0,1,2这三个数组索引的内容。
function setDynamicArrayData() {
dynamicArray[0] = 0xa7;
dynamicArray[1] = 0xbf;
dynamicArray[2] = 0xdd;
}
//获取字节数组内容。
function getDynamicArrayData() view returns(bytes) {
return dynamicArray;
}
//设置字节数组成员对象的长度为5.
//多出来的长度内容,用‘00’填空每个索引数据。
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(string){
return stringStr[index];
}
*/
//获取指定字符串内容 √
// 要获取字符串的指定索引元素,需要先将其转为字节才行。
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 dynamicArrayBytes = new bytes(bytesVariable.length);//因为缺少 memory关键字将其定义为引用类型,因此编译失败。
// memory是solidity中的关键字,意思是将改变量声明为引用类型。
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;
//return string(bytesDynamicArray); 这样也可以。
}
}
二.普通数组
普通数组,就是非字节类型的数组,用法和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;// 结果:12,2,86,21,3
}
//为所有下标索引赋值并打印
function getArrayB() public view returns(uint[5]){
arrayB[0] = 1;
arrayB[1] = 3;
arrayB[2] = 5;
arrayB[3] = 7;
arrayB[4] = 9;
return arrayB;//结果:1,3,5,7,9
}
//仅为前两个下标索引赋值并打印
function getArrayC() public view returns(uint[5]){
arrayC[0] = 6;
arrayC[1] = 8;
return arrayC;//结果:6,8,0,0,0
}
}
二.动态长度数组
定义格式:数据类型[] 变量名;
例如:uint[] arrayB;
pragma solidity ^0.4.16;
contract dynamicArray {
uint[] arrayA = [1,3,5,7,9];
uint[] arrayB;
//对原先长度为5的动态数组,将其长度设为8,并赋值和打印输出。
function setLengthAndGetDataOfArrayA() public view returns(uint[]){
arrayA.length = 8;
arrayA[5] = 212;
arrayA[6] = 712;
arrayA[7] = 612;
return arrayA;//结果:1,3,5,7,9,212,712,612
}
//将原先未定义长度的动态数组,对其长度设为2,并赋值和打印输出。
function setLengthAndGetDateOfArrayB() public view returns(uint[]){
arrayB.length = 2;
arrayB[0] = 6;
arrayB[1] = 2;
arrayB.push(1212);// push方法,将一个新元素添加到末端。
return arrayB;// 结果:6,2,1212
}
}
三.固定二维数组
格式:数据类型[二维数组长度][一维数组长度] 变量名;
例如: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];// [44,33]
}
//对二维数组中的某个元素赋值,并打印输出。
function setAndGetUintDimensionArrayByIndex() public view returns(uint[2]){
uintDimensionArray[1] = [222,111];
return uintDimensionArray[1];// [222,111]
}
}
四.动态二维数组
格式:数据类型[][] 变量名;
例如:string[][] strArray;
动态二维数组和固定二维数组不同的是,动态二维数组不支持直接获取所有元素内容,只能获取单个索引的元素内容。
pragma solidity ^0.4.16;
contract dynamicDimensionArray {
string[][] strArray = [["hello","world!"],["hi","solidity!"]]; // 动态二维数组 字符串类型
uint[][] uintArray = [[11,22],[33,44]];//动态二维数组 int类型
/* 动态二维数组不支持直接获取所有元素。
function getUintArrayAll() public view returns(uint[][]){
return uintArray;// 不可以直接获取动态二维数组所有元素,编译报错: UnimplementedFeatureError: Nested dynamic arrays not implemented here.
}*/
//获取单个指定字符串类型动态二维数组的元素。
function getStrArrayByIndex() public view returns(string){
return strArray[0][1];//输出结果: world
}
//向字符串类型动态二维数组添加元素,并打印。
function addElementAndGetStrArrayByIndex() public view returns(string){
strArray.push(["你好","同学"]);
return strArray[2][0];//输出结果:你好
}
//获取int类型二维动态数组的长度
function getUintArrayLength() public view returns(uint){
return uintArray.length;
}
//获取单个指定int类型动态二维数组的元素。
function getUintArrayByIndex() public view returns(uint[]){
return uintArray[0];//输出结果: [11,22]
}
//向int类型动态二维数组添加元素,并打印。
function addElementAndGetUintArrayByIndex() public view returns(uint[]){
uintArray.push([1233,3214]);
return uintArray[2];//输出结果: [1233,3214]
}
}
三.数组字面(直接创建并返回)
说到‘数组字面’可能你不理解这是什么,但如果用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 {
//最大数值为251,可以用8位,也就是uint8位数
function getUintFor8bit() public view returns(uint8[3]){
return [251,32,3];
}
//最大数值达到了256,使用uint8位数会编译出错,必须用uint16位数
/*function getUintFor256bit() public view returns(uint8[3]){
return [256,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];// 通过‘uint(元素值)’的形式进行位数强转。
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)