在 Solidity 中,`view` 和 `pure` 函数之间有什么区别?

Carlos Howard
Carlos Howard
Blockchain architect with 8 years' Ethereum experience; 8年以太坊开发经验的区块链架构师。

好的,没问题。我们来聊聊 Solidity 里的 viewpure,这俩兄弟其实挺好区分的。

viewpure 的区别:一个只能看,一个连看都不看

想象一下你走进一家餐厅:

  • view 函数就像是看菜单:你可以查看菜单上所有的菜品、价格、描述(读取合约的状态),但你不能去后厨自己改菜单(修改合约的状态)。你看完菜单后,餐厅本身没有任何变化。
  • pure 函数就像是你自己带的计算器:你用它算账,比如 2 + 3 = 5。这个计算过程完全不依赖于餐厅的菜单(不读取合约状态),更不会改变菜单(不修改合约状态)。它只和你输入给它的数字有关。

下面我们来详细拆解一下。


view 函数 (只读函数)

你可以把它理解成一个“只读”或者“观察者”函数。

  • 承诺:我保证不会修改合约里的任何数据。
  • 能做什么:它可以读取合约的状态变量。比如,一个合约里记录了 owner 是谁,或者一个 ERC20 代币的总供应量 totalSupply 是多少,view 函数都可以把这些信息读出来告诉你。
  • 不能做什么:不能修改任何状态变量(比如 owner = newAddress 就不行),不能发出事件(emit),也不能调用其他会修改状态的函数。

简单代码示例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleStorage {
    uint256 public myNumber = 42; // 这是一个状态变量

    // 这个函数读取状态变量 myNumber 的值
    // 它只 "看" 不 "改", 所以是 view
    function getMyNumber() public view returns (uint256) {
        return myNumber;
    }
}

在这个例子里,getMyNumber() 只是去读取 myNumber 的值并返回,它没有改变任何东西,所以我们把它标记为 view


pure 函数 (纯函数)

这个更严格,你可以叫它“纯粹的计算函数”。

  • 承诺:我不仅不修改合约数据,我连看都懒得看。
  • 能做什么:它只能使用函数调用时传给它的参数,或者函数内部定义的局部变量来进行计算和返回结果。它与合约的存储状态完全隔离。
  • 不能做什么:所有 view 函数不能做的事它都不能做,而且它还不能读取合约的状态变量

简单代码示例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleCalculator {
    // 这个函数只依赖于输入的 a 和 b
    // 它和合约本身的状态没有任何关系, 所以是 pure
    function add(uint256 a, uint256 b) public pure returns (uint256) {
        return a + b;
    }
}

你看,这个 add 函数就像一个独立的计算器,你给它 ab,它就返回它们的和。它完全不关心合约里存了什么数据。


总结一下,一张图看懂

特性view 函数pure 函数
读取合约状态变量✅ 可以不可以
修改合约状态变量❌ 不可以❌ 不可以
依赖输入参数进行计算✅ 可以✅ 可以
比喻像个图书管理员,只能查阅资料像个计算器,只处理你给它的数

关键点来了:为什么要区分它们?

区分 viewpure 不仅仅是为了让代码更清晰,更重要的是为了省 Gas

  1. 外部调用免费:当你在合约外部(比如通过 web3.js 从你的网站前端)调用一个 viewpure 函数时,这个操作是完全免费的,不消耗任何 Gas。因为它只是读取数据,没有在区块链上创建新的交易。这对于向用户展示链上数据非常有用。

  2. 内部调用省 Gas:当一个合约函数 A 调用另一个 viewpure 函数 B 时,虽然会消耗 Gas,但通常比调用一个会修改状态的函数要便宜得多,因为它们不会执行昂贵的存储写入操作。

所以,作为一名合格的智能合约开发者,养成正确使用 viewpure 的好习惯非常重要。如果你的函数逻辑上不需要修改或读取状态,就一定要把它标记为 pureview,这既能让代码更安全、意图更明确,也能为用户省下真金白银。