【跟乐乐学solidity】一 基础:字节数组普通数组与字符串 *** 作

【跟乐乐学solidity】一 基础:字节数组普通数组与字符串 *** 作,第1张

前言

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(元素值)’的形式进行位数强转。
    }
    
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/925804.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存