以太坊开发学习-solidity(三)函数类型
目录
函数类型
函数类型
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)
internal
pure
returns (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
)
internal
pure
returns (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];
}
// 命名式返回,依然支持return
function 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();
}
}