solidity 官方文档里把函数归到数值类型,但我觉得差别很大,所以单独分一类。我们先看一下 solidity 中函数的形式:
function () {internal|external|public|private} [pure|view|payable] [returns ()]
Copy
看着些复杂,咱们从前往后一个一个看(方括号中的是可写可不写的关键字):
我刚开始学solidity的时候,一直不理解pure跟view关键字,因为别的语言没有类似的关键字。solidity加入这两个关键字,我认为是因为gas fee。合约的状态变量存储在链上,gas fee很贵,如果不改变链上状态,就不用付gas。包含pure跟view关键字的函数是不改写链上状态的,因此用户直接调用他们是不需要付 gas 的(合约中非pure/view函数调用它们则会改写链上状态,需要付 gas)。
在以太坊中,以下语句被视为修改链上状态:
我画了一个马里奥插画,帮助大家理解。在插画里,我把合约中的状态变量(存储在链上)比作碧池公主,三种不同的角色代表不同的关键字。
我们在合约里定义一个状态变量 number = 5。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract FunctionTypes{
uint256 public number = 5;
Copy
定义一个add()函数,每次调用,每次给number + 1。
// 默认
function add() external{
number = number + 1;
}
Copy
如果add()包含了pure关键字,例如 function add() pure external,就会报错。因为pure(纯纯牛马)是不配读取合约里的状态变量的,更不配改写。那pure函数能做些什么?举个例子,你可以给函数传递一个参数 _number,然后让他返回 _number+1。
// pure: 纯纯牛马
function addPure(uint256 _number) external pure returns(uint256 new_number){
new_number = _number + 1;
}
Copy
Example:
如果add()包含view,比如function add() view external,也会报错。因为view能读取,但不能够改写状态变量。可以稍微改写下方程,让他不改写number,而是返回一个新的变量。
// view: 看客
function addView() external view returns(uint256 new_number) {
new_number = number + 1;
}
// internal: 内部
function minus() internal {
number = number - 1;
}
// 合约内的函数可以调用内部函数
function minusCall() external {
minus();
}
Copy
我们定义一个internal的minus()函数,每次调用使得number变量减 1。由于是internal,只能由合约内部调用,而外部不能。因此,我们必须再定义一个external的minusCall()函数,来间接调用内部的minus()。 Example:
// payable: 递钱,能给合约支付eth的函数
function minusPayable() external payable returns(uint256 balance) {
minus();
balance = address(this).balance;
}
Copy
我们定义一个external payable的minusPayable()函数,间接的调用minus(),并且返回合约里的ETH余额(this关键字可以让我们引用合约地址)。 我们可以在调用minusPayable()时,往合约里转入 1 个ETH。
我们可以在返回的信息中看到,合约的余额是 1 ETH。
Example:
在这一讲,我们介绍了solidity中的函数类型,比较难理解的是pure和view,在其他语言中没出现过。solidity引入pure和view关键字主要是为了节省gas和控制函数权限:如果用户直接调用pure/view方程是不消耗gas的(合约中非pure/view函数调用它们则会改写链上状态,需要付 gas)。