---
title: "Solidity 中的 struct 是什么？"
description: "了解 Solidity struct 的作用、工作原理及使用场景"
---

# Solidity 中的 struct 是什么？

[Solidity](https://www.alchemy.com/overviews/solidity) 中有不同的基本数据类型，比如 [_uint_（无符号整数）](https://www.alchemy.com/overviews/solidity-uint)、_bool_ 和 _string_，但作为区块链开发者，你可能需要一种可以自行定义的灵活数据类型。**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 编译器](https://www.alchemy.com/overviews/solidity-compiler)前面的类型是一个自定义类型
1. 为 struct 命名，该名称将与 struct 中打包的变量相互对应
1. 使用花括号，因为其他任何形式的括号（比如方括号或圆括号）都无法通过编译

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

<ImageBlock
  src="https://media.alchemy.com/1704181525-parsererror-message.png"
  alt="未在结构体中使用花括号时，Remix 编译器给出的 ParserError 信息。"
  width={809}
  height={185}
  caption="未在结构体中使用花括号时，Remix 编译器给出的 ParserError 信息。"
/>

      4. 声明数据类型及其对应的变量

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

#### **开发者提示：**

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

### 如何声明 Solidity struct

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

#### **在合约外部声明 struct**

在上面的例子中，_floorOverlay_ struct 是在[智能合约](https://www.alchemy.com/overviews/solidity-smart-contract)外部声明的，代码库中的所有合约都可以调用它。相较于只服务于单个合约的特定 struct，在智能合约外部声明 struct 能创建出更通用、适用于所有合约的 struct。

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

#### **在合约内部声明 struct**

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

### 如何导入 Solidity struct

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

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

### **如何在 Solidity 中初始化 struct**

即使你已经声明并创建了 struct，如果不为它赋予某个初始值，也无法在[各种 Solidity 函数](https://www.alchemy.com/overviews/solidity-modifier)中使用它。初始化 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 中，以便更方便地定位某个特定成员。此外，[嵌套映射](https://www.alchemy.com/overviews/solidity-mapping)可以更方便地追踪 DAO 成员的地址以及他们是否已经投票。

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

<ImageBlock
  src="https://media.alchemy.com/1704181857-remix-error.png"
  alt="尝试将结构体声明为键类型时，Remix 显示的错误。"
  width={935}
  height={160}
  caption="尝试将结构体声明为键类型时，Remix 显示的错误。"
/>

## **总结——Solidity 中 struct 的本质是什么？**

Solidity 中的 struct 让开发者能够创建适合自身构建需求的自定义类型。这些自定义类型就像是容器，将多个相关的数据类型汇集在一起。想要深入了解 struct，欢迎报名 [Alchemy University 的 Solidity 训练营](https://www.alchemy.com/university/courses/solidity?a=53bceeeaa3)！
