基于以太坊的智能合约开发Solidity(数组提升篇)

2023-12-13 05:39:46

参考教程:【数据存储篇】1、string内存原理——特殊动态数组_哔哩哔哩_bilibili

1、语法——字符串:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract DynamicString
{

? ? string name = "lalalalalalala啦啦啦";
? ? 
? ? function getLength() public returns(uint)
? ? {
? ? ? ? return bytes(name).length; ?//要想获取字符串的长度,需要先将其强制转换成动态长度字节数组(string不提供长度属性)
? ? }
? ? 
? ? function getPartName() public returns(bytes1)
? ? {
? ? ? ? return bytes(name)[0]; ?//返回字符串第一个字符(1个字节)的二进制形式(不能直接通过数组下标的形式获取其中的字符)
? ? }
? ? 
? ? function changeName() public 
? ? {
? ? ? ? bytes(name)[0] = 'T'; ?//对字符串的某一个字符进行修改
? ? ? ? //一个英文字母(以及特殊字符和数字等)占1个字节,一个中文汉字占3个字节
? ? }
}

(1)要想获取字符串的长度,需要通过bytes()先将其强制转换成动态长度字节数组(string不提供长度属性)。

(2)对于string,不能通过数组下标的形式获取其中的某个字符

(3)一个汉字占3个字节,这是因为汉字在内存中是通过UTF8类型存储的,至于一些特殊字符和数字则是占用一个字节

2、语法——字节数组转换:

(1)固定长度字节数组转为固定长度字节数组:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract DynamicString
{
? ? 
? ? bytes12 name = ?0x7a68656e676a69616e78756e;
? ? 
? ? function changeBytes1() public view returns(bytes1)
? ? {
? ? ? ? return bytes1(name); ?//返回的结果为“0x7a”,后面的内容全部丢失
? ? }
? ? 
? ? function changeByte2() public view returns(bytes2)
? ? {
? ? ? ? return bytes2(name); ?//返回的结果为“0x7a68”,后面的内容全部丢失
? ? }
? ? 
? ? function changeByte3() public view returns(bytes16)
? ? {
? ? ? ? return bytes16(name); ?//返回的结果为“0x7a68656e676a69616e78756e00000000”,强制转换后多余的空间由0填充
? ? }
}

(2)固定长度字节数组转为动态长度字节数组:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract DynamicString
{
? ? 
? ? bytes12 name = ?0x7a68656e676a69616e78756e;
? ? 
? ?function fixBytesToDynamicBytes() public view returns(bytes memory)
? ?{
? ? ? ?//return bytes(name); ?不允许直接将字符串的强制类型转换返回,需要借助for循环将固定长度字节数组复制到动态长度字节数组中
? ? ? ?bytes memory newName = new bytes(name.length); ?//方法内的动态长度字节数组要加“memory”,这里暂时不做解释
? ? ? ?for(uint i = 0; i < name.length; i++) ?//数组元素下标的数据类型只能是uint,除此之外for循环的使用与c语言基本相同(if语句、while语句以及相关关键字的用法也基本相同)
? ? ? ?{
? ? ? ? ? ?newName[i] = name[i]; ?//复制行为
? ? ? ?}
? ? ? ?return newName;
? ?}
}

(3)动态长度字节数组转为字符串:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract Bytes2String
{
? ? 
? ? bytes name = ?new bytes(2);
? ? 
? ? function init() public
? ? {
? ? ? ? name[0] = 0x7a;
? ? ? ? name[1] = 0x68;
? ? }
? ? 
? ? function bytesToString() public view returns(string memory)
? ? {
? ? ? ? return string(name); ?//允许将动态长度字节数组强制转换字符串的结果直接返回
? ? }
}

(4)固定长度字节数组转为字符串:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract Bytes32ToString
{
? ? 
? ? function byts32ToString(bytes32 inputName) ?public view returns(string memory)
? ? {
? ? ? ? uint count = 0; ?//定义一个无符号变量记录字节数组的实际长度,否则转换而得的字符串尾部会有不定量的NUT字符
? ? ? ? 
? ? ? ? for(uint i = 0; i < inputName.length; i++) ?//利用for循环计算inputName数组的实际长度
? ? ? ? {
? ? ? ? ? ? if(inputName[i] != 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? count++;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? 
? ? ? ? bytes memory finalName = new bytes(count); ?//动态长度字节数组的初始长度为inputName数组的实际长度
? ? ? ? //利用for循环将固定长度字节数组转换为动态长度字节数组,再强制转换为字符串
? ? ? ? for(uint j = 0; j<count; j++)
? ? ? ? {
? ? ? ? ? ? finalName[j] = inputName[j]; ?//复制行为
? ? ? ? }
? ? ? ? 
? ? ? ? return string(finalName);
? ? }
?
}

3、语法——数组与函数结合使用:

(1)固定长度数组:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract FixArray
{
? ?//(定义语法:数据类型[元素个数] 数组名)
? ?uint[5] arr = [1,2,3,4,5]; ?//定义时可以不进行初始化,那么初值将会全部置为0
? ?
? ?function init() public
? ?{
? ? ? ?arr[0] = 100; ?//可以对单个元素值进行修改
? ? ? ?arr[1] = 200;
? ?}
? ?
? ?function sumArr() public view returns(uint)
? ?{
? ? ? ?uint sum = 0;
? ? ? ?for(uint i = 0; i < arr.length; i++) ?//除了数组元素下标是uint类型以外,其它地方和c语言基本相同
? ? ? ?{
? ? ? ? ? ?sum += arr[i];
? ? ? ?}
? ? ? ?
? ? ? ?return sum;
? ?}
? ?//固定长度数组可以通过length获取其长度,但是不能对其长度进行更改,也不能进行push操作
}

(2)可变长度数组:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract DynamicArray
{
? ? 
? ?uint[] arr = [1,2,3,4,5]; ?//在定义数组时不写出元素个数,就是定义可变长度数组

? ?function changeLength() public
? ?{
? ? ? ? arr.length = 1; ?//对可变长度数组的长度进行缩短,原数组的多余部分会丢失
? ?}
? ?
? ?function changeLength2() public
? ?{
? ? ? ? arr.length = 10; ?//对可变长度数组的长度进行增长,多余部分用0填充
? ?}
? ?
? ?function getContent() public view returns(uint[] memory)
? ?{
? ? ? ? return arr; ?//可以直接将数组(不管长度是否可变)作为返回值返回(也可以将数组作为参数传入)
? ?}
? ?
? ?function getLength() public view returns(uint)
? ?{
? ? ? ? return arr.length;
? ?}
? ?
? ?function push() public
? ?{
? ? ? ? arr.push(6); ?//在可变长度数组末尾追加元素6
? ?}
?
}

可以直接将数组(不管长度是否可变)作为返回值返回(也可以将数组作为参数传入),作为返回值时,需注意returns声明的数据类型要与返回值严格相同(对于固定长度数组,声明的元素个数要与返回的元素个数相同,作为参数传入函数时也同理)。

4、语法——二维数组:

(1)固定长度二维数组:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract TwoArray
{
? ?uint[2][3] arr = [[1,2],[3,4],[5,6]]; ?//与大多数编程语言不同,solidity定义二维数组时先声明列数再声明行数(个人认为比较别扭)
? ?
? ?function getLength() public view returns(uint)
? ?{
? ? ? ?return arr.length; ?//该例中返回3,代表有3个元素(其中每个元素自己又由2个元素组成)
? ?}
?
? ?function getContent() public view returns(uint[2][3] memory)
? ?{
? ? ? ?return arr; ?//可以将二维数组作为返回值直接返回(输出“unit256[2][3]:1,2,3,4,5,6”,是线性表示的)
? ?}

? ?function add() public view returns(uint)
? ?{
? ? ? ?uint sum = 0;
? ? ? ?//遍历二维数组需要借助嵌套循环
? ? ? ?for(uint i = 0; i<arr.length; i++) ?//arr.length代表arr中有3行
? ? ? ?{
? ? ? ? ? ?for(uint j=0; j<arr[0].length; j++) ?//arr.length[0]代表arr中每一行有2个元素(即2列)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?sum += arr[i][j]; ?//虽然二维数组的声明比较别扭,但使用时和c语言基本也完全一样
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?return sum;
? ?}
}

(2)可变长度二维数组:

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract DynamicTwoArray
{
? ? 
? ?uint[][] arr = [[1,2],[3,4],[6,7]];? //可变长二维数组初始化时不允许每个一维数组长度不相同
? ?
? ?/*
? ?function getContent() ?public view returns(uint[][] memory)
? ?{
? ? ? ?return arr; ?//动态长度数组不支持直接返回
? ?}
? ?*/
? ?
? ?function changeLength() public
? ?{
? ? ? ? arr.length = 10; ?//修改二维数组的行数
? ?}
? ?
? ?function getLength() public view returns(uint)
? ?{
? ? ? ? return arr.length; ?//二维数组的行数
? ?}
? ?
? ?function getContntLength() public view returns(uint) 
? ?{
? ? ? ? return arr[0].length; ?//二维数组的列数
? ?}
?
}

5、语法——数组字面量(数组常量):

//声明版本号(程序中的版本号要和编译器版本号一致)
pragma solidity ^0.5.17;
//合约
contract ArrayLiterals
{
? ?/* 
? ?function getArrayLiterals() public returns(uint[3] memory)
? ?{
? ? ? ?return [1,2,3]; ?//uint默认为256位,但是1、2、3都是uint8类型,类型不匹配,会报错
? ?}
? ?
? ?function getArrayLiterals2() public returns(uint[3] memory)
? ?{
? ? ? ?return [256,255,3]; ?//uint默认为256位,但是256是uint16类型,类型不匹配,会报错(255、3是uint8类型)
? ?}
? ?*/
? ?function getArrayLiterals1() public view returns(uint16[3] memory)
? ?{
? ? ? ?return [256,2,3]; ?//解决办法1:让声明的返回值类型和实际返回值匹配(将返回值参数中的类型改为数组元素中最大值的类型)
? ?}
? ?function getArrayLiterals2() public view returns(uint[3] memory)
? ?{
? ? ? ?return [uint(256),2,3]; ?//解决办法2:让实际返回值类型和声明返回值匹配
? ?}
}

文章来源:https://blog.csdn.net/Zevalin/article/details/134889590
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。