Solidity 数组与字符串简介

本文详细介绍了Solidity中的数组和字符串数据结构,包括它们的声明、使用方式以及一些重要的概念如calldatamemory。还提供了多个代码示例来帮助理解这些概念。

在本节中,我们将介绍数组数据结构和字符串数据结构。这些行为与我们之前讨论的 Solidity 数据类型有所不同,所以我们将在这里讨论它们。

数组声明的语法

让我们看一个处理数组并返回数组的函数。这里有很多内容需要解读!

首先,应该清楚的是,声明一个数字数组的语法是 uint256[]。我们稍后会讨论 calldatamemory

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;
    }
}

那么 calldatamemory 是什么呢?首先,如果不包括它们,代码将无法编译。以下是两段无法编译的代码示例。

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;
    }
}

那么 calldatamemory 是什么?

如果你熟悉 C 或 C++,这个概念将是直观的。在 Solidity 中,内存就像 C、C++ 或 Rust 中的堆。数组可以具有无限大小,因此将其存储在执行栈中(如果你不知道那是什么也没关系),可能会导致 stackoverflow 错误(不要与著名的论坛混淆!)。

Calldata 是 Solidity 特有的。它是当有人将交易发送到区块链时实际的“交易数据”。

Calldata 意味着“引用以太坊交易本身的数据。”这个概念相对高级,所以如果你现在无法完全理解也没关系。

当有疑问时:数组和字符串的函数参数应为 calldata,而返回类型的函数参数应为 memory。

在函数参数使用 calldata 还有一些例外,但数组的返回类型应该始终是 memory,而不是 calldata,否则代码无法编译。为了不让你感到信息过载,关于 calldata 的例外,我们将稍后讨论。

下面是如何在 Remix 中使用数字数组。

Untitled 1

数组是零索引的,像其他语言一样

这里没有惊喜。

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; // 不编译
    }
}

我们遗漏的内容

  • Solidity 中的数组支持像 pop() 这样的操作,但这会产生更高级的副作用,因此我们会在之后讲解。
  • 在函数内部声明数组和字符串,与在参数或返回值中声明它们的语法不同。

练习题

FizzBuzz

SumArray

FilterOddNumbers

IsSorted

Mean

学习更多

查看 集训营,以了解有关智能合约开发和代币标准的更多信息。

  • 原文链接: rareskills.io/learn-soli...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/