Solidity编程语言:字符串、数组
字符串
字符串的定义使用单引号或双引号都可以。这里主要说一下有关string的常见操作,在solidity中不是很方便。
pragma solidity >=0.4.0 <0.6.0; //import "github.com/Arachnid/solidity-stringutils/strings.sol"; contract EgString { string name = 'buff'; string addr = "beijing"; unction getAddrLength()public returns(uint){ return bytes(addr).length;//获取字符串 } function concatenateWithAbi ()public returns(string memory){ return string(abi.encodePacked(name, addr)); } /*function concatenateWithGit() public returns(string memory){ return name.toSlice().concat(addr.toSlice()); }*/ function compare1() public returns(bool){ return keccak256(bytes(name)) == keccak256(bytes(addr)); } function compare2() public returns (bool){ for (uint i = 0; i < bytes(name).length; i ++) { if(bytes(name)[i] != bytes(addr)[i]) { return false; } } } /* // parseInt(parseFloat*10^_b) function parseInt(string memory _a, uint _b) internal returns (uint) { bytes memory bresult = bytes(_a); uint mint = 0; bool decimals = false; for (uint i=0; i<bresult.length; i++){ if ((bresult[i] >= 48)&&(bresult[i] <= 57)){ if (decimals){ if (_b == 0) break; else _b--; } mint *= 10; mint += uint(bresult[i]) - 48; } else if (bresult[i] == 46) decimals = true; } if (_b > 0) mint *= 10**_b; return mint; } function uint2str(uint i) internal returns (string memory) { if (i == 0) return "0"; uint j = i; uint len; while (j != 0){ len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len - 1; while (i != 0){ bstr[k--] = byte(48 + i % 10); i /= 10; } return string(bstr); }*/ }
长度
字符串长度的获取需要将string转换成bytes,然后使用bytes的length属性获取长度。
拼接
- 字符串拼接, 官网 上给出的方法是使用abi.encodePacked方法。
- 也可以自己写一个方法,思路就是把string转换成bytes,然后将bytes合并成一个大的bytes,最后再将结果bytes转换成string。其中bytes与string转换方法为bytes(string),string(bytes),这里就不写代码了。
- 网上有人使用 git 上的一个工具包,不过我自己编译一直通不过,后续再查下原因。浏览了下代码,可以学习下。 比较Solidity同样不支持字符串的比较,需要自己实现,这里提供两种方式(这里不包含其他的工具包方式),当然出于性能要求以及gas消耗情况,可以首先对字符串的长度进行比较,然后再比较内容。这个 文章 写的不错,而且有gas消耗测试统计。
- 比较两字字符串的hash是否相等。
- 逐个比较每个字符 int转换 Solidity同样不支持string与int的互相转换。这里可以直接查看工具类 oraclize 。其转换思路就是把string首先转换成bytes类型,然后逐个遍历,进行数值累加。
在solidity中,数组分为固定长度数组和不固定长度数组,顾名思义就是在声名后的数组长度是否可以发生变化。
固定长度数组
pragma solidity >=0.4.0 <0.6.0; contract EgFixedArray { uint[5] arr1 = [1,2,3,4,5]; //uint[5] arr1 = []; //uint[5] arr2 = new uint[](5); function modifyLen()public{ // arr1.length = 2;编译失败 } function modifyElement()public { arr1[1] = 3; } function pushToArray() public{ // arr1.push(1);编译失败 } }
- 固定长度数组必须初始化元素,并且无法通过new来创建。
- 固定长度数组的长度length属性是不可以修改的,否则会报编译错误。
- 固定长度数组元素是可以修改的,但是需要通过索引操作。
- 固定长度数组不可以使用push方法,编译无法通过,不固定长度数组。
pragma solidity >=0.4.0 <0.6.0; contract EgUnFixedArray { //uint[] arr1 = [1,2,3,4,5]; uint[] arr1 = new uint[](5); function modifyLen()public{ arr1.length = 2; } function modifyElement()public { arr1[1] = 3; } function pushToArray() public { arr1.push(1); } }
- 不固定长度数组,可以通过new来声名,元素默认取值为数组类型的默认值。
- length可以修改,如果修改的length小于原先,则数组元素从后往前被去掉。
- 元素可以修改。
- 可以使用push方法,push之后数据长度加一,push方法返回的是数组的长度memory修饰数组。
function modifyMemoryArr() public returns(uint){ uint8[5] memory arr2 = [1,2,3,4,5]; // arr2.push(6); // arr2.length = 6; return arr2.length; }
- memory修饰的数组必须指定数组长度。
- memory修饰的数组不能使用push方法。
- memory修饰的数组不能修改length属性。
function inputArr(uint[5] arr) public{ // arr.length = 6; // arr.push(6); }
对于方法参数是数组类型的参数,其默认也是memory修饰的,所以也无法使用length属性和push方法。
function assignment() public{ // uint[] memory x = [uint(1), 3, 4]; // uint[] x = [uint(1), 3, 4]; uint[3] memory x = [uint(1), 3, 4]; uint[] memory x1 = new uint[](3); }
- 固定长度数组不能赋值于memory修饰的不固定长度数组。
- 不固定长度数组不能使用数组字面量进行赋值。
function testReturn1() public returns(uint[3] memory){ uint[3] memory u1 = [uint(1),2,3]; return u1; } function testReturn2() public returns(uint[] memory){ uint[] memory u2 = new uint[](5); return u2; }
备注:网上有看到说是返回值不能使用不固定长度数组,我使用0.5.2的solidity版本验了一下是可以的,有可能是旧版本不行。
作者:感谢HPB Wallet 开发团队整理供稿。
汪晓明博客 http://wangxiaoming.com/
汪晓明:HPB芯链创始人,巴比特专栏作家。十余年金融大数据、区块链技术开发经验,曾参与创建银联大数据。主创区块链教学视频节目《明说》30多期,编写了《以太坊官网文档中文版》,并作为主要作者编写了《区块链开发指南》,在中国区块链社区以ID“蓝莲花”知名。