本文详细介绍了Solidity中的数组和字符串数据结构,包括它们的声明、使用方式以及一些重要的概念如calldata
和memory
。还提供了多个代码示例来帮助理解这些概念。
在本节中,我们将介绍数组数据结构和字符串数据结构。这些行为与我们之前讨论的 Solidity 数据类型有所不同,所以我们将在这里讨论它们。
数组声明的语法
让我们看一个处理数组并返回数组的函数。这里有很多内容需要解读!
首先,应该清楚的是,声明一个数字数组的语法是 uint256[]
。我们稍后会讨论 calldata
和 memory
。
contract ExampleContract {
function useArrayForUint256(uint256[] calldata input)
public
pure
returns (uint256[] memory) {
return input;
}
}
如果你想要一个地址或布尔值的数组,则为以下内容:
contract ExampleContract {
function booleanArrayExample(bool[] calldata input)
public
pure
returns (bool[] memory) {
return input;
}
function addressArrayExample(address[] calldata input)
public
pure
returns (address[] memory) {
return input;
}
}
那么 calldata
和 memory
是什么呢?首先,如果不包括它们,代码将无法编译。以下是两段无法编译的代码示例。
contract BadContract1 {
// 参数缺少 calldata
function useArrayForUint256(uint256[] input)
public
pure
returns (uint256[] memory) {
return input;
}
}
contract BadContract2 {
// 返回类型缺少 memory
function useArrayForUint256(uint256[] calldata input)
public
pure
returns (uint256[]) {
return input;
}
}
那么 calldata
和 memory
是什么?
如果你熟悉 C 或 C++,这个概念将是直观的。在 Solidity 中,内存就像 C、C++ 或 Rust 中的堆。数组可以具有无限大小,因此将其存储在执行栈中(如果你不知道那是什么也没关系),可能会导致 stackoverflow 错误(不要与著名的论坛混淆!)。
Calldata 是 Solidity 特有的。它是当有人将交易发送到区块链时实际的“交易数据”。
Calldata 意味着“引用以太坊交易本身的数据。”这个概念相对高级,所以如果你现在无法完全理解也没关系。
当有疑问时:数组和字符串的函数参数应为 calldata,而返回类型的函数参数应为 memory。
在函数参数使用 calldata
还有一些例外,但数组的返回类型应该始终是 memory,而不是 calldata,否则代码无法编译。为了不让你感到信息过载,关于 calldata 的例外,我们将稍后讨论。
下面是如何在 Remix 中使用数字数组。
数组是零索引的,像其他语言一样
这里没有惊喜。
contract ExampleContract {
function returnFirstElement(uint256[] calldata myArray)
public
pure
returns (uint256) {
uint256 first = myArray[0];
return first;
}
}
注意返回类型是 uint256,因为我们返回的是一个数字,而不是数组。
注意如果数组为空,交易将会回滚。
要获取数组的长度,使用 .length
这与 JavaScript 是一样的。
contract ExampleContract {
function returnFirstElement(uint256[] calldata myArray)
public
pure
returns (uint256) {
uint256 len = myArray.length;
return len;
}
}
这也是你可以循环遍历数组的方式。
contract ExampleContract {
function productOfarray(uint256[] calldata myArray)
public
pure
returns (uint256) {
uint256 product = 1;
for (uint256 i = 0; i < myArray.length; i++) {
product *= myArray[i];
}
return product;
}
}
数组可以声明为固定长度
在之前的示例中,声明时方括号内没有内容。如果你想强制数组具有固定大小,可以在方括号内放入大小。
contract ExampleContract {
function productOfarray(uint256[5] calldata myArray)
public
pure
returns (uint256) {
uint256 last = myArray[4];
return last;
}
}
如果函数传入的数组大小不是 5,则会回滚。
字符串
字符串的行为与数组非常相似。事实上,在底层它们就是数组(但有一些差异)。下面是一个返回你传入的字符串的函数。
contract ExampleContract {
function echo(string calldata input)
public
pure
returns (string memory) {
return input;
}
}
这是 hello world 最终版本。
contract ExampleContract {
function helloWorld()
public
pure
returns (string memory) {
return "Hello, world!";
}
}
字符串连接
有趣的是,Solidity 在2022年2月之前并不支持字符串连接,当时 Solidity 0.8.12 版本发布。如果你想在 Solidity 中进行字符串连接,请确保文件顶部的 pragma 至少为 0.8.12。
pragma solidity ^0.8.12;
contract ExampleContract {
function useArrays(string calldata user)
public
pure
returns(string memory) {
return string.concat("hello ", user);
}
}
字符串连接的支持被如此晚加入是有原因的,因为智能合约通常处理数字,而不是字符串。
字符串无法索引
在 JavaScript 或 Python 等语言中,你可以像处理数组一样索引字符串并获取一个字符。Solidity 不能这样做。以下代码无法编译。
pragma solidity ^0.8.12;
contract BadContract {
function useArrays(string calldata input)
public
pure
returns(string memory) {
return input[0]; // 错误
}
}
字符串不支持长度
Solidity 不支持获取字符串的长度。这是因为 unicode 字符可能导致长度模糊不清,而 Solidity 将字符串表示为字节数组,而不是字符序列。
pragma solidity ^0.8.12;
contract StringContract {
function useArrays(string calldata input)
public
pure
returns(uint256) {
return input.length; // 不编译
}
}
我们遗漏的内容
练习题
查看 集训营,以了解有关智能合约开发和代币标准的更多信息。
- 原文链接: rareskills.io/learn-soli...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!