---
title: "Solidity 中的 events 是什么？"
description: "了解 Solidity Events 的工作原理"
---

# Solidity 中的 events 是什么？

[Solidity](https://www.alchemy.com/overviews/solidity) 事件对智能合约开发者而言至关重要，因为它们允许智能合约对变量进行索引以重建存储状态，有助于自动更新用户界面，并支持对特定变量进行测试。本文将帮助你加深对 Solidity 事件的理解，[进一步深入学习 Solidity 编程语言](https://www.alchemy.com/university/courses/solidity?a=d7f2788ae5)。

我们将首先介绍 Solidity 事件，然后给出它们的分类，并提供示例。读完本文后，你将能够为下一个项目创建 Solidity 事件。

## **什么是 Solidity 中的事件？**

**在 Solidity 中，事件是智能合约可以触发的已分发信号。** 当你调用事件时，参数会被存储在交易的日志中，这是区块链上一种特殊的数据结构。事件会通知外部用户——比如监听中的前端网站或客户端应用程序——区块链上发生了某些事情。

### **Solidity 中事件与函数有什么区别？**

**函数和事件都接受参数并可以被调用，但函数会直接修改智能合约，而事件的作用是通知区块链之外的服务，让用户知道发生了某些事情。**

[Solidity 中的函数](https://www.alchemy.com/overviews/solidity-functions)允许开发者在智能合约中读取、写入、更改和存储数据。你可以向函数传入参数，也可以在代码中需要的任何地方调用函数。

事件同样接受参数，但这些参数存储在交易日志中，智能合约无法访问该日志。合约数据存放在 State trie 中，而事件数据存储在 Transaction Receipts trie 中，这意味着合约无法读取事件数据。

与函数一样，事件也可以被调用。不过，调用/触发事件使用的是 _emit_ 关键字。这让开发者能够知道某个事件或函数何时被调用。

### 事件与日志之间是什么关系？

Ethereum 的 Log 数据结构用于存储事件发出的数据。

以太坊虚拟机（EVM）具有日志记录功能，用于将数据（包括 Solidity 事件）写入智能合约之外的结构中。

日志和事件常被视为同义词。事件让你能够以更省 gas 的方式将信息“打印”到日志结构中，因为这些信息不会存储在会占用更多 gas 的存储变量中。事件（或日志）存放在 Transaction Receipts trie 中，智能合约无法访问该结构。

#### **Solidity 中事件是如何被索引的？**

**Solidity 事件是与 EVM 日志功能对接的接口。** 你最多可以为三个参数添加 indexed 属性。这样它们会出现在日志的 topics 结构中，而不是数据部分。当参数没有 indexed 属性时，它们会被 ABI 编码进日志的数据部分。

## **Solidity 事件类型**

Solidity 事件分为两种类型：已索引的和未索引的。

当参数没有 indexed 属性时，它们会被 [ABI 编码](https://www.alchemy.com/overviews/solidity-abi)进日志的数据部分。这些参数构成事件的字节数组。数据会根据其类型进行编码，也可以根据某种模式（schema）进行解码。

已索引的参数也被称为“topics”，是事件中可供搜索的参数。已索引的参数让你能够以这些参数作为过滤条件来搜索相应事件。根据事件是否为匿名事件，你最多可以分别为 4 个或 3 个参数添加 indexed 属性。

## **Solidity 中事件是如何运作的？**

**Solidity 事件的生命周期包括声明、触发和注册。**

1. 首先，需要使用 Solidity 中的 _event_ 关键字声明事件类型。
1. 接下来，使用 emit 关键字触发该事件。
1. 每当区块链上发生变化时，你的程序会自动记录这一变化并触发该事件。

**注意：** 在声明之后触发事件，可以让你使用 [Web3.js](https://www.alchemy.com/dapps/web3-js) 或 Ethers.js 等库在应用程序中“监听”该事件。

### **如何在 Solidity 中声明事件？**

**事件的声明包含事件名称，以及触发事件时你希望保存的参数。**

首先，你需要在 Solidity 中声明一个事件。然后，使用 _emit_ 关键字触发该事件。

以下是声明事件的示例：

事件被触发时，会通知外部应用程序区块链上发生了某些变化。

### **Solidity 中事件是如何被触发的？**

事件定义完成后，你可以使用 emit 关键字来触发该事件。事件被触发后，传入的参数会被存储在交易日志中。

以下语法展示了如何在 Solidity 中使用 emit：

## **如何在 Solidity 中监听事件**

事件被触发后，你可以通过订阅来捕获这些事件，从而对其进行监听，可以使用 [ethers.js](https://www.alchemy.com/dapps/ethers-js)。此后，[应用程序](https://www.alchemy.com/dapps/top/defi-dapps)，或任何连接到 Ethereum JSON-RPC API 的程序，都可以监听这些事件并作出相应处理。

### **Solidity 事件示例**

以下示例代码定义并触发了一个用于转账的事件。此代码适用于以太坊转账应用程序，在转账发生时触发该事件。你还可以添加额外的代码，让事件在触发时更新用户界面，以显示转账已完成。

<ImageBlock
  src="https://media.alchemy.com/1703866327-solidity-event-example.png"
  alt="定义并触发 Transfer 事件的 Solidity 代码示例"
  width={1600}
  height={743}
  caption="定义并触发 transfer 事件"
/>

下一个示例取自 **Solidity by Example**，创建了一个包含两个参数的事件：发送者地址和字符串消息。触发时，该事件会记录 “Hello World” 和 “Hello EVM”。

<ImageBlock
  src="https://media.alchemy.com/1703866441-solidity-event-with-two-parameters.png"
  alt="包含两个参数（发送方地址和消息字符串）的事件的 Solidity 代码示例"
  width={1558}
  height={890}
  caption="带两个参数的事件"
/>

## **继续学习 Solidity**

本文向你介绍了 Solidity 事件，并提供了相关说明和资源，供你在下一个项目中使用。掌握 Solidity 事件后，你将能够更轻松地创建高效的智能合约。

如果你刚接触 Solidity 语言，并期待构建你的第一个智能合约，欢迎报名参加 Alchemy University 免费的、为期 7 周的[在线 Solidity 编程课程](https://www.alchemy.com/university/courses/solidity?a=d7f2788ae5)。
