跳至内容
0%

Solidity 中的 struct 是什么?

发布于 2022年10月4日2 分钟阅读

Solidity 中有不同的基本数据类型,比如 uint(无符号整数)boolstring,但作为区块链开发者,你可能需要一种可以自行定义的灵活数据类型。struct(结构体)是 Solidity 中的一种数据结构格式,可以将不同数据类型的变量捆绑到一个变量或自定义类型中。

本文将向你介绍 Solidity 中的 struct,说明它们的作用及工作原理。最后,我们会讲解如何使用 struct 来编写更健壮的智能合约。

什么是 Solidity struct?

struct 是 Solidity 中一种便于创建的数据结构格式,可以将不同数据类型的变量捆绑到一个变量或自定义类型中。 一旦这些数据类型被归入一个 struct,struct 的名称就代表了其中的变量子集。

可以把 struct 想象成装有不同类型物品的容器,当你移动这个容器时,里面的所有物品也会跟着一起移动。因此,当 Solidity 开发者声明或调用某个 struct 的名称时,该 struct 会根据其内部的数据类型做出相应的响应。

以下是一个 Solidity struct 的示例:

上面这个 struct 示例包含了变量 address creator、string name、address users 和 uint amount。

Solidity struct 代码示例

本节将展示 Solidity 中定义和创建 struct 的示例代码。我们还会演示 struct 声明可用的两种方式。最后,我们会说明如何导入和初始化 struct。

如何在 Solidity 中定义和创建 struct

struct 的代码写法与 Javascript 中对象的声明方式有些相似。虽然形式上很相近,但两者的语法运作方式并不相同。Solidity struct 始终遵循以下格式:

以下是定义和创建 Solidity struct 的方法:

  1. 使用 struct 关键字创建一个 struct,这会告诉 Solidity 编译器前面的类型是一个自定义类型
  2. 为 struct 命名,该名称将与 struct 中打包的变量相互对应
  3. 使用花括号,因为其他任何形式的括号(比如方括号或圆括号)都无法通过编译

如果你不使用花括号,Remix 会生成如下的 ParserError 报错信息。

未在结构体中使用花括号时,Remix 编译器给出的 ParserError 信息。
未在结构体中使用花括号时,Remix 编译器给出的 ParserError 信息。
  1. 声明数据类型及其对应的变量

在上面的例子中,这些是 string theWord、uint theFigure 和 bool polarData。这一步就是声明 struct 变量子集的地方。在智能合约中声明 struct 之后,我们就可以在代码后续部分调用该 struct 的名称。

开发者提示:

  • 只能使用花括号
  • struct 的每个成员都要以分号结尾
  • 如果你声明的数据类型与输入的变量不匹配,Solidity 会抛出错误
  • 智能合约可以包含多个 struct,它们通过各自的关键字来区分

如何声明 Solidity struct

有两个地方可以声明 struct:在合约内部,或在合约外部。选择在哪里声明 struct 取决于你想要实现的目标。我们来看看这两种 struct 声明方式。

在合约外部声明 struct

在上面的例子中,floorOverlay struct 是在智能合约外部声明的,代码库中的所有合约都可以调用它。相较于只服务于单个合约的特定 struct,在智能合约外部声明 struct 能创建出更通用、适用于所有合约的 struct。

此外,如果你希望多个智能合约共用同一批 struct,最好在 pragma 之后立即声明它,而不是在每个智能合约中分别单独创建 struct。

在合约内部声明 struct

carpet struct 位于智能合约内部,因此该 struct 的功能范围仅限于当前合约,其他任何合约都无法调用它的名称。

如何导入 Solidity struct

struct 可以从一个智能合约导入到另一个智能合约,这有助于开发者节省时间并编写可复用的代码。为了演示如何导入 struct,下面给出两个智能合约:一个是创建 struct 的合约,另一个是导入该 struct 的合约。

导入时有一个需要避免的错误:第二个合约的名称应与你要导入的 struct 名称一致,否则 Solidity 编译器将无法识别它,从而导致错误。

如何在 Solidity 中初始化 struct

即使你已经声明并创建了 struct,如果不为它赋予某个初始值,也无法在各种 Solidity 函数中使用它。初始化 struct 有 3 种方式:(i)键值对方式,(ii)先定义后更新方式,(iii)参数括号方式。

1. 键值对方式

使用这种方式时,你需要选取 struct 中的每个键类型,并为其赋值。

这种方式的语法并不严格,你可以不必按照 struct 中类型的顺序来赋值。

2. 先定义后更新方式

这种初始化方式的语法是:先输入一个变量来存储该 struct,然后使用这个变量来访问并为 struct 的每个成员赋名赋值。以下代码是一个示例:

不过要注意,大多数开发者并不使用这种方式,因为它写起来比较长。

3. 参数括号方式

如果要使用这种方式,你需要调用 struct 的名称、存储其内存,并按顺序为 struct 的成员赋值。示例如下:

这里,“measles” 是存储该初始化结果的变量,我们还按照 struct 中的定义声明了各个参数。请务必将声明的名称放在括号内并用引号括起来,以便 Solidity 编译器能够识别它。

Solidity struct 使用场景

本节演示一个 Solidity 使用场景:在合约中追踪用户信息。在这个场景中,struct 被用于映射。

Solidity 中 struct 可以被映射吗?

在 Solidity 中,struct 可以作为值类型被映射,这样你就可以追踪 struct 中任意成员的相关信息。 来看下面的代码示例:

在这个合约中,某个 DAO 中每个成员的详细信息都被归类整理。我们在这里创建了两个映射:一个是简单映射,另一个是嵌套映射。

在简单映射中,我们将每个成员的地址映射到 struct 中,以便更方便地定位某个特定成员。此外,嵌套映射可以更方便地追踪 DAO 成员的地址以及他们是否已经投票。

由于映射始终遵循 key type => value type 的语法,struct 必须始终被声明为值类型,而不能作为键类型,否则会出现错误。

尝试将结构体声明为键类型时,Remix 显示的错误。
尝试将结构体声明为键类型时,Remix 显示的错误。

总结——Solidity 中 struct 的本质是什么?

Solidity 中的 struct 让开发者能够创建适合自身构建需求的自定义类型。这些自定义类型就像是容器,将多个相关的数据类型汇集在一起。想要深入了解 struct,欢迎报名 Alchemy University 的 Solidity 训练营

Background gradient

构建区块链应用

Alchemy 将最强大的 Web3 开发者产品和工具与资源、社区及专业支持结合在一起。