目录
函数类型
函数类型
solidity官方文档里把函数归到数值类型
函数类型是一种表示函数的类型。可以将一个函数赋值给另一个函数类型的变量, 也可以将一个函数作为参数进行传递,还能在函数调用中返回函数类型变量。
函数类型有两类:- 内部(internal) 函数和 外部(external) 函数:
1. 内部函数只能在当前合约内被调用(更具体来说, 在当前代码块内,包括内部库函数和继承的函数中), 因为它们不能在当前合约上下文的外部被执行。 调用一个内部函数是通过跳转到它的入口标签来实现的, 就像在当前合约的内部调用一个函数。
2.外部函数由一个地址和一个函数签名组成,可以通过外部函数调用传递或者返回
函数形式
function <function name>(<parameter types>) {internal|external|public|private} [pure|view|payable] [returns (<return types>)]
看着些复杂,咱们从前往后一个一个看(方括号中的是可写可不写的关键字):
function
:声明函数时的固定用法,想写函数,就要以function关键字开头。
<function name>
:函数名。
(<parameter types>)
:圆括号里写函数的参数,也就是要输入到函数的变量类型和名字。
{internal|external|public|private}
:函数可见性说明符,一共4种。没标明函数类型的,默认public
。合约之外的函数,即"自由函数",始终具有隐含internal
可见性。
public
: 内部外部均可见。private
: 只能从本合约内部访问,继承的合约也不能用。external
: 只能从合约外部访问(但是可以用this.f()
来调用,f
是函数名)。internal
: 只能从合约内部访问,继承的合约可以用。Note 1: 没有标明可见性类型的函数,默认为
public
。Note 2:
public|private|internal
也可用于修饰状态变量。public
变量会自动生成同名的getter
函数,用于查询数值。Note 3: 没有标明可见性类型的状态变量,默认为
internal
。
[pure|view|payable]
:决定函数权限/功能的关键字。payable
(可支付的)很好理解,带着它的函数,运行的时候可以给合约转入ETH
。pure
和view
的介绍见下一节。
[returns ()]
:函数返回的变量类型和名称。
使用内部函数类型的例子
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;library ArrayUtils {// 内部函数可以在内部库函数中使用,因为它们将是同一代码上下文的一部分function map(uint[] memory self, function (uint) pure returns (uint) f)internalpurereturns (uint[] memory r){r = new uint[](self.length);for (uint i = 0; i < self.length; i++) {r[i] = f(self[i]);}}function reduce(uint[] memory self,function (uint, uint) pure returns (uint) f)internalpurereturns (uint r){r = self[0];for (uint i = 1; i < self.length; i++) {r = f(r, self[i]);}}function range(uint length) internal pure returns (uint[] memory r) {r = new uint[](length);for (uint i = 0; i < r.length; i++) {r[i] = i;}}
}contract Pyramid {using ArrayUtils for *;function pyramid(uint l) public pure returns (uint) {return ArrayUtils.range(l).map(square).reduce(sum);}function square(uint x) internal pure returns (uint) {return x * x;}function sum(uint x, uint y) internal pure returns (uint) {return x + y;}
}
使用外部函数类型的例子
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;contract Oracle {struct Request {bytes data;function(uint) external callback;}Request[] private requests;event NewRequest(uint);function query(bytes memory data, function(uint) external callback) public {requests.push(Request(data, callback));emit NewRequest(requests.length - 1);}function reply(uint requestID, uint response) public {// 这里要检查的是调用返回是否来自可信的来源requests[requestID].callback(response);}
}contract OracleUser {Oracle constant private ORACLE_CONST = Oracle(address(0x00000000219ab540356cBB839Cbe05303d7705Fa)); // 已知的合约uint private exchangeRate;function buySomething() public {ORACLE_CONST.query("USD", this.oracleResponse);}function oracleResponse(uint response) public {require(msg.sender == address(ORACLE_CONST),"Only oracle can call this.");exchangeRate = response;}
}
返回值 return 和 returns
Solidity
有两个关键字与函数输出相关:return
和returns
,他们的区别在于:
returns
加在函数名后面,用于声明返回的变量类型及变量名;return
用于函数主体中,返回指定的变量。
// 返回多个变量function returnMultiple() public pure returns(uint256, bool, uint256[3] memory){return(1, true, [uint256(1),2,5]);}
上面这段代码中,我们声明了returnMultiple()
函数将有多个输出:returns(uint256, bool, uint256[3] memory)
,接着我们在函数主体中用return(1, true, [uint256(1),2,5])
确定了返回值。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;// 返回多个变量
// 命名式返回
// 解构赋值contract Return {// 返回多个变量function returnMultiple() public pure returns(uint256, bool, uint256[3] memory){return(1, true, [uint256(1),2,5]);}// 命名式返回function returnNamed() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){_number = 2;_bool = false; _array = [uint256(3),2,1];}// 命名式返回,依然支持returnfunction returnNamed2() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){return(1, true, [uint256(1),2,5]);}// 读取返回值,解构式赋值function readReturn() public pure{// 读取全部返回值uint256 _number;bool _bool;bool _bool2;uint256[3] memory _array;(_number, _bool, _array) = returnNamed();// 读取部分返回值,解构式赋值(, _bool2, ) = returnNamed();}
}