Renaissance Labs

發布於 2022-02-24到 Mirror 閱讀

Learn Solidity Series 4: arrays

Learn Solidity Series

Solidity中,有两种类型的数组:存储数组和内存数组。

存储数组(Storage Arrays)

这些数组被声明为状态变量,并且可以具有固定长度或动态长度。动态存储数组可以调整数组的大小,它们通过访问push()pop()方法来调节长度。

// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

contract A { uint256[] public numbers;// 动态长度数组 address[10] private users; // 固定长度数组 uint8 users_count;

  function addUser(address _user) external {
      require(users_count < 10, "number of users is limited to 10");
      users[users_count] = _user;
      users_count++;
  }
  
  function addNumber(uint256 _number) external {
      numbers.push(_number);
  }

内存数组(Memory Arrays)

这些数组以memory作为其数据位置声明。它们也可以具有固定长度或动态长度,但是不能调整动态大小的内存数组的大小(即,不能调用push()pop()方法),数组的大小必须预先计算。也可以使用new关键字声明动态大小的内存数组。

Type[] memory a = new Type

// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

contract B {

 function createMemArrays() external view {
     uint256[20] memory numbers;
     numbers[0] = 1;
     numbers[1] = 2;
     
     uint256 users_num = numbers.length;
     address[users_num] memory users1; // 错误 :  应该是整数常量或常量表达式

     address[] memory users2 = new address[](users_num);
     users2[0] = msg.sender; // OK
     users2.push(msg.sender); // 错误 : member push is not available
     
 }
}

注意,numbers[0] = 1; 因为根据内存中布局的描述,array将指向零插槽,因此切勿写入。请记住,在使用数组之前,请务必先对其进行初始化,以便获取有效的地址。

数组切片(Array Slices)

数组切片只能与calldata数组一起使用,形式为x[start:end]。切片的第一个元素是x [start],最后一个元素是x[end-1]。开始和结束都是可选的:开始默认为0,结束默认为数组的长度。

byte[]和bytes

这些数组可以保存任意长度的原始字节数据。

区别在于,byte []遵循数组类型的规则,并且如文档 Solidity中的内存数组的描述,数组的元素总是占据32个字节的倍数。这意味着如果一个元素的长度小于32字节的倍数,则将对其进行填充,直到其适合所需的大小为止。对于byte数组,每个元素将浪费31个字节。值得说明的是,从内存中读取或写入一个字(32个字节)会消耗 3 gas,这就是为什么建议使用bytes而不是byte[]的原因。

而bytes或string不是这种情况。string字符串是UTF-8数据的动态数组。与其他语言相反,Solidity中的string不提供获取字符串长度或执行两个字符串的连接或比较的功能(需要使用库)。 可以使用bytes()将字符串转换为字节数组。这将返回字符串的UTF-8表示形式的低级字节。

注意:可以将一个字符编码为一个以上的字节,因此字节数组的长度不一定是字符串的长度。

string与bytes

文档的大多数使用bytes32而不是string,并且如果可以限制字符串的字节数,则应该使用值类型bytes1 ... bytes32,因为便宜得多。