乐闻世界logo
搜索文章和话题

Solidity 中的 view、pure 和 payable 函数修饰符有什么区别?

3月7日 12:09

在 Solidity 中,viewpurepayable 是三种重要的函数修饰符,它们定义了函数的行为特性和限制条件。

1. View 修饰符

定义:声明函数不会修改合约的状态变量,但可以读取状态。

特点

  • 可以读取状态变量(storage)
  • 不能修改状态变量
  • 不能发送 ETH
  • 不消耗 Gas(当被外部调用时)
solidity
contract ViewExample { uint256 public storedData = 100; // view 函数可以读取状态 function getData() public view returns (uint256) { return storedData; // 读取状态变量 } // 错误:view 函数不能修改状态 function setData(uint256 _data) public view { // storedData = _data; // 编译错误! } }

2. Pure 修饰符

定义:声明函数既不读取也不修改合约状态,仅依赖于输入参数。

特点

  • 不能读取状态变量
  • 不能修改状态变量
  • 不能访问 msg.sendermsg.value 等全局变量
  • 不消耗 Gas(当被外部调用时)
solidity
contract PureExample { uint256 public constant VALUE = 100; // pure 函数只依赖输入参数 function add(uint256 a, uint256 b) public pure returns (uint256) { return a + b; } // pure 函数可以读取常量 function getConstant() public pure returns (uint256) { return VALUE; // 常量不算状态读取 } // 错误:pure 函数不能读取状态变量 function getData() public pure returns (uint256) { // return storedData; // 编译错误! } }

3. Payable 修饰符

定义:允许函数接收 ETH(以太币)。

特点

  • 可以接收 ETH 转账
  • 可以读取和修改状态(默认行为)
  • 可以访问 msg.value 获取转账金额
  • 消耗 Gas
solidity
contract PayableExample { mapping(address => uint256) public balances; // payable 函数可以接收 ETH function deposit() public payable { require(msg.value > 0, "Must send ETH"); balances[msg.sender] += msg.value; } // 查询合约余额 function getBalance() public view returns (uint256) { return address(this).balance; } // 提取 ETH function withdraw(uint256 amount) public { require(balances[msg.sender] >= amount, "Insufficient balance"); balances[msg.sender] -= amount; payable(msg.sender).transfer(amount); } }

修饰符对比表

特性viewpurepayable
读取状态
修改状态
接收 ETH
访问 msg.value
Gas 消耗(外部调用)
适用场景查询数据纯计算资金操作

组合使用

某些修饰符可以组合使用:

solidity
contract CombinedExample { // payable + view 不能组合,因为 view 不消耗 Gas,而 payable 需要处理转账 // 可以定义接收 ETH 的函数 receive() external payable {} fallback() external payable {} // 计算函数使用 pure function calculateFee(uint256 amount) public pure returns (uint256) { return amount * 5 / 100; // 5% 手续费 } // 查询函数使用 view function getContractBalance() public view returns (uint256) { return address(this).balance; } }

实际应用示例

solidity
contract Bank { mapping(address => uint256) private balances; uint256 public totalDeposits; // payable:接收存款 function deposit() public payable { balances[msg.sender] += msg.value; totalDeposits += msg.value; } // view:查询余额 function getBalance(address user) public view returns (uint256) { return balances[user]; } // pure:计算利息 function calculateInterest(uint256 principal, uint256 rate) public pure returns (uint256) { return principal * rate / 100; } // payable + 其他操作 function withdraw() public payable { uint256 amount = balances[msg.sender]; require(amount > 0, "No balance"); balances[msg.sender] = 0; totalDeposits -= amount; payable(msg.sender).transfer(amount); } }

最佳实践

  1. 优先使用 pure:如果函数不需要读取状态,使用 pure 可以节省 Gas
  2. 明确使用 view:对于只读操作,明确标记 view 提高代码可读性
  3. 谨慎使用 payable:确保 payable 函数有适当的访问控制和金额验证
  4. 避免滥用:不要为了 Gas 优化而错误地使用这些修饰符,可能导致安全问题
标签:Solidity