前言
一、函数可见性visility
1.public
2.private
3.external
4.internal
二、函数状态易变性mutability
1.view
2.pure
3.payable
4.non-payable
三、函数修改器modifiy(类似python的装饰器、js的@decorator)
四、函数returns
五、receive&fallback是什么?
六、构造函数和析构函数
七、返回值
八、call函数
九、函数类型变量
总结
1.定义函数:有函数体{}
2.声明函数,没有函数体{}
3.声明函数变量:function (uint) external returns (uint) name;
solidity函数结构:
function function_name(
不能数字开头 uint public view returns(uint, value_name){... no return,因为外面参数有}
int private pure returns (return_type) {... return}
string external payable
address internal none(不用写)
array none(不用写)
一、函数可见性visiblity
函数的可见性有四种:
this
。)public 和external类型函数有一个熟悉 selector
function f() internal view returns (bytes4) {
return this.f.selector;
}
函数的可见性有四种:
view
声明的函数只能读取状态,而不能修改状态。pure
声明的函数既不能读取也不能修改状态。payable
声明的函数可以接受发送给合约的以太币,如果未指定,该函数将自动拒绝所有发送给它的以太币。contract trans{
uint256 public value;
constructor() payable{
value = msg.value;
}
function number()public view returns(uint256){
return value;
}
function n()public payable returns(uint256){
value = msg.value;
return msg.value;
}
}
contract SimpleStorage {
uint256 private data;
function getData() external view returns(uint256) {
return data;
}
function setData(uint256 _data) external {
data = _data;
}
}
3.1当你要在执行函数之前检查某些条件时,可以使用修饰器。例如,如果你要检查发件人是否是合约的所有者,则可以编写以下内容:
function selectWinner() external {
require(msg.sender == owner, "this function is restricted to the owner);
...}
3.2使用修饰器,我们可以分离该代码,以便我们可以将其与其他函数复用,我们只需要声明修饰器,如下所示:
modifier onlyOwner(){
require(msg.sender == owner, "this function is restricted to the owner);
_; // will be replaced by the code of the function
return 10;
}
然后将修饰器名称添加到函数中:
// 如果函数修改器onlyOwner中 _;后面还有语句,就接着执行
function selectWinner() external onlyOwner {
return 7;
// 如果函数修改器onlyOwner中 _;后面还有语句,就接着执行 return 10;
}
多重modifier的执行顺序,很重要!!!
函数可以返回任意数量的值作为输出。有两种方法从函数返回变量:
1. 使用返回变量名:
function arithmetic(uint _a, uint _b) public pure
returns (uint o_sum, uint o_product)
{
o_sum = _a + _b;
o_product = _a * _b;
}
2. 直接在return语句中提供返回值:
function arithmetic(uint _a, uint _b) public pure
returns (uint o_sum, uint o_product)
{
return (_a + _b, _a * _b);
}
合约最多可以具有一个fallback
函数(一般翻译为回退函数)。这个函数不能有参数,不能返回任何参数,并且必须具有external
可见性。如果其他函数均不匹配给定的函数签名,或者根本没有提供任何数据并且没有receive
函数,则在调用合约时执行该函数。
5.1receive,往合约地址发送eth,成功,调用receive。
当向合约发送Ether且未指定调用任何函数(calldata 为空)时执行。这是在普通的以太坊转账上执行的函数(例如,通过.send()
或.transfer()
转账)。
receive() external payable{}
5.2fallback,
fallback() external payable{}
fallback函数特点:
不能有返回值。
合约最多可以具有一个fallback
函数(一般翻译为回退函数)。这个函数不能有参数,不能返回任何参数,并且必须具有external
可见性。如果其他函数均不匹配给定的函数签名,或者根本没有提供任何数据并且没有receive
函数,则在调用合约时执行该函数。
5.2.1 当给合约转以太币时,必须有payable回退函数。
5.2.2 当调用合约不存在的函数时,就会掉用回退函数
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.0;
contract ReceiveEther {
string public data;
receive() external payable {
data = "receive call";
}
fallback() external payable {
data = "fallback call";
}
function getBalance() public view returns (uint){
return address(this).balance;
}
}
fallback在接收以太币时,仅有2300gas来执行,下面操作会失败,因为消耗大于2300gas:
1.写存储(storage)
2.创建一个合约
3.执行外部(external)函数调用,会花费非常多的gas
4.发送ether
FallBack函数的实用场景
场景一:空投
利用FallBack函数,用户只需要使用钱包向空投合约发送0金额的转账(只消耗手续费),空投合约就可以向该地址进行空投。
场景二:锁仓
用户使用钱包将代币转账到锁仓合约中,锁仓合约利用FallBack函数接收到请求,就可以执行锁仓逻辑了。
构造函数 constructor
析构函数deconstructor(0.5以下版本才有):kill,生命周期结束时释放内存,
pragma solidity ^0.4.13;
// construct构造函数和析构函数
contract MyCoin{
uint public amount;
address owner;
constructor(uint _data) public{
amount=_data;
owner=msg.sender;
}
function getBalance() public view returns (uint){
return amount;
}
function kill() public{ // 析构函数
if(owner==msg.sender){
selfdestruct(owner);
}
}
}
// 函数可以返回多个值
function multipleReturns() returns(uint a, uint b, uint c) {
return (1, 2, 3);
}
// 同时接收所有返回值
function processMultipleReturns() {
uint a;
uint b;
uint c;
// 这样来做批量赋值:
(a, b, c) = multipleReturns();
}
//只接收部分返回值:或者如果我们只想返回其中一个变量:
function getLastReturnValue() {
uint c;
// 可以对其他字段留空:
(,,c) = multipleReturns();
}
八、call函数,
lowlevel底层通信,合约之间根据address调用方法
pragma solidity ^0.4.0;
// call函数 call()是一个底层的接口,用来向一个合约发送消息[1],也就是说如果你想实现自己的消息传递,可以使用这个函数。
// 函数支持传入任意类型的任意参数,并将参数打包成32字节,相互拼接后向合约发送这段数据。
contract Person{
uint age = 10;
string public data;
function increaseAge(string memory name, uint num) public returns (uint){
string memory name2 = name;
uint num2 = num;
return ++age;
}
function getAge() public view returns (uint){
return age;
}
function() external {
data = "fallback call";
}
}
contract CallTest{
function callByFun(address addr) public returns (bool){
// bytes4 methodId = bytes4(keccak256("increaseAge(string,uint256)"));
// return addr.call(methodId,"jack", 1);
// 下面这句等于上面2行
return addr.call(abi.encodeWithSignature("increaseAge(string, uint256)","jack",2));
}
function callData(address addr) public returns (bool){
return addr.call("abc", 256); // 找不到abc函数,会调fallback函数
}
}
九、函数类型变量
pragma solidity ^0.4.18;
contract TestFunc {
function a(uint x) external returns (uint z) {
return x * x;
}
function b(uint x) external returns (uint z) {
return 2 * x;
}
// 变量f 可以被赋值为函数a 或 函数b
function select(function (uint) external returns (uint) f, uint x) external returns (uint z) {
return f(x);
}
// 函数作为返回值的类型
function getfun() public view returns (function (uint) external returns (uint) ) {
return this.b;
}
function callTest(bool useB, uint x) external returns (uint z) {
// 变量f 可以被赋值为 函数a 或 函数b
function (uint) external returns (uint) f;
if (useB) {
f = this.b;
} else {
f = this.a;
}
return f(x);
}
// 0x26121ff0
function f() public view returns (bytes4) {
return this.f.selector;
}
}
solidity函数结构:
function function_name(
不能数字开头 uint public view returns(uint, value_name){... no return}
int private pure returns (return_type) {... return}
string external payable
address internal none(不用写)
array none(不用写)