区块链学习(Solidity函数)【Day10-11 | 5.25-5.26】

函数

基础概念

函数定义

  • 函数定义语法
function function_name(<parameter list>) <visibility> <state mutability>
    [ returns(<return type>)]{
        // 语句
    }
  • 可见性(visibility)
    • private(私有):函数只能在所定义的智能合约内部调用
    • internal(内部):可以在所定义合约内部调用该函数,也可以从继承合约中调用该函数
    • external(外部):只能从合约外部调用。如果要从合约中调用它,则必须使用this。
    • public(公开):可以从任何地方调用
  • 状态可变性(mutability)
    • view:用 view 声明的函数只能读取状态,而不能修改状态
    • pure:用 pure 声明的函数既不能读取也不能修改状态
    • payable:用 payable 声明的函数可以接受发送给合约的以太币,如果未指定,该函数将自动拒绝所有发送给它的以太币。
  • 示例
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract SoldityTest{
        constructor(){}
        function getResult() public view returns(uint){
            uint a = 1;     // 局部变量
            uint b = 2;
            uint result = a+b;
            return result;
        }
    }

函数调用

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SolidityTest{
    constructor(){}

    function getResult() public pure returns(string memory){
        return integerToString(3);  // 调用函数 integerToString
    }

    // integerToString 函数定义
    function integerToString(uint _i)internal pure
        returns(string memory){
            if(_i == 0){
                return "0";
            }
            uint j = _i;
            uint len;
            while(j!=0){
                len++;
                j/=10;
            }
            bytes memory bstr = new bytes(len);
            uint k = len - 1;
            while(_i != 0){
                bstr[k--] = bytes1(uint8(48 + _i % 10));
                _i /= 10;
            }
            return string(bstr);
        }
}

return 语句

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test{
    function getResult() public view returns(uint product,uint sum){
        uint a = 1;     // 局部变量
        uint b = 2;
        product = a*b;  // 使用返回参数返回值
        sum = a+b;      // 使用返回参数返回值

        // 也可以使用 return 返回多个值
        // return(a*b,a+b);
    }
}

函数返回值

  • 函数返回值可以使用名字,也可以使用匿名方式
  • 可以通过名字赋值,也可以使用 return 返回
  • 支持多个返回值
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract funreturn{

    // 返回值可以有名字
    function returnTest() public view returns(uint mul){
        uint a = 10;
        return a;
    }

    // 可以直接为返回值赋值
    function returnTest2()public view returns(uint mul){
        mul = 10;
    }

    // 当给返回值赋值后,并且有多个 return,以最后的 return 为主
    function returnTest3() public view returns(uint mul){
        uint a = 10;
        mul = 100;
        return a;
    }  

    // 返回常量,自动匹配
    function returnTest4() public view returns(uint mul){
        uint a = 10;
        mul = 100;
        return 1;
    }

    // 函数可以有多个返回值,多返回值赋值
    function returnTest5(uint a,uint b)public view returns(uint add,uint mul){
        add = a+b;
        mul = a*b;
    }

    // 函数可以有多返回值,返回 return(param list)
    function returnTest6(uint a,uint b)public view returns(uint add,uint mul){
        return(a+b,a*b);
    }

    // 交换变量的值
    function returnTest7(uint a,uint b)public view returns(uint a1,uint b1){
        return(b,a);
    }
}
  • 函数多返回值的调用方法
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract funreturn{
    // 定义多返回值函数
    function returnFunc() private pure returns(uint a,uint b){
        return(1,2);
    }

    // 调用多返回值函数
    function callFunc1() public pure returns(uint,uint){
        (uint r1,uint r2) = returnFunc();
        return (r1,r2);
    }
    
    // 调用多返回值函数,先定义变量
    function callFunc2() public pure returns(uint,uint){
        uint r1;
        uint r2;
        (r1,r2) = returnFunc();
        return(r1,r2);
    }

    // 调用多返回值函数,但只取第一个返回值
    function callFunc3() public pure returns(uint,uint){
        (uint r1,) = returnFunc();
        return(r1,100);
    }
}

pure 函数

  • pure 函数(纯函数),指函数不会读取或修改状态,即不会操作链上数据
  • 如果函数中存在以下语句,则被视为读取状态,编译器将抛出警告
    • 读取状态变量
    • 访问 address(this).balance 或 <address>.balance
    • 访问任何区块、交易、msg等reshuffle变量(msg.sig 与 msg.data 允许读取)
    • 调用任何不是纯函数的函数
    • 使用包含特定操作码的内联程序集
  • 如果发生错误,pure 函数可以使用 revert() 和 require() 函数来还原潜在的状态更改
  • 声明为 pure函数,可以在函数声明里,添加 pure 关键字
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test {
   function getResult() public pure returns(uint product, uint sum){
      uint a = 1; 
      uint b = 2;
      product = a * b;
      sum = a + b; 
   }

View 函数

  • view 函数,也就是视图函数,是指函数只会读取状态,不会修改状态
    • 也就是说 view 函数只会读取链上数据,不会修改链上数据
  • 如果函数中存在以下语句,则会被视为修改状态,编译器将抛出警告
    • 修改状态变量
    • 触发事件
    • 创建合约
    • 使用 selfdestruct
    • 发送以太
    • 调用任何不是视图函数或纯函数的函数
    • 使用底层调用
    • 使用包含某些操作码的内联程序集
  • 状态变量的 Getter 方法默认是 view 函数
  • 声明为 view 视图函数,可以在函数声明里,添加 view 关键字
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ViewDemo{
    uint factor = 2;    // 状态变量

    function getResult(uint num) public view returns(uint){
        uint result = num * factor;
        return result;

    /*  在这个例子中,函数getResult中,只是读取了状态变量factor的值,而没有修改它的值,所以这个函数是一个view函数。 */
    }
}

构造函数

  • 构造函数是一个特殊函数,它仅能在合约部署的时候调用一次,之后就不能再次被调用
    • 常用来进行状态变量的初始化工作
    • 使用 constructor 作为构造函数
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test{
    uint a;

    // 不带参数的构造函数
    constructor(){
        a = 0;
    }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test{
    uint a;
    
    // 带参数的构造函数
    constructor(uint _a){
        a = _a;
    }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test {
   int public a ;
   address public owner;

   constructor(int _a) public{
     // 将部署者地址存储到owner变量
      owner = msg.sender;
    // 将参数_a存储到a变量
      a = _a;
   }    
}


函数修改器

  • modifier 用于声明一个函数修改器
    • 可以将通用的操作提取出来,包装为函数修改器,来提高代码复用性,改善编码效率
    • modifier 的作用与 Java Spring 的切面功能很相似,当它作用于一个函数上,可以在函数执行前或后预先执行 modifier 中的逻辑,以增强其功能
    • modifier 常用于在函数执行前检查某种前置条件
    • modifier 是一种合约属性,可被继承,同时还可被派生的合约重写(override)
  • 基本函数修改器
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ModifierTest{
    bool public paused;
    uint public counter;

    function setPaused(bool _paused)external{
        paused = _paused;
    }

    modifier isNotPaused(){
        require(!paused);   // 检查前置条件,判断paused是否被设置,如果paused为true那么终止执行
        _;      // 执行被 isNotPaused 修饰的函数
    }

    function add() external isNotPaused(){
        counter++;
    }
}

/*    add函数被修改器isNotPaused修饰,所以先执行 require(!paused),检查前置条件,然后再执行add函数的代码。    */
  • _ 的作用
    • 函数修改器中有一行代码只有下划线 _ ,我们认为下划线 _ 代表了被修饰函数的代码
    • 下划线实际上帮我们标记了被 modifier 修饰函数的执行位置
  modifier isNotPaused(){
        require(!paused);   // 检查前置条件,判断paused是否被设置,如果paused为true那么终止执行
        _;      // 执行被 isNotPaused 修饰的函数
}

/* 下划线 _在 require(!paused) 后面,则被修饰函数 add 在此判断条件之后执行。 */
  • 带参数的函数修改器
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ModifierTest{
    bool public paused;
    uint public counter;

    function setPaused(bool _pasued) external{
        paused = _pasued;
    }

    modifier isNotPaused(uint x){
        require(x>10);  // 检查前置条件:判断x是否大于10,如果x大于或者等于10,那么终止执行
        _;              // 执行被 isNotPaused 修饰的函数
    }

    function add(uint x)external isNotPaused(x){
        counter++;
    }
}
  • 复杂示例
    • 函数修改器经典的应用 OpenZeppelin 库中的 Ownable 合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/*  Ownable 可以判断合约的调用者是否为当前合约的 owner
    从而避免其他人随意的调用一些合约的关键操作
    同时,owner 可以指定任何其他人为此合约新的 owner
    显然,只有当前 owner 才能指定其他人为新的 owner */

    contract Ownable{
        // 变量 owner 指定此合约的 owner
        address public owner;
        // 发布时间 - 此合约 owner 已经换人(此逻辑于 modifier 无关,可以忽略)
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

        // 构造函数 创建合约自动执行,初始化合约所有人为合约创建者
        constructor(){
            owner = msg.sender;
            
        }

        // 定义一个函数修改器
        modifier onlyOwner(){
            // 判断此函数调用者是否为 owner
            require(msg.sender == owner);
            _;
        }

        // owner 可以用此函数将 owner 所有权转换给其他人,显然此函数只有 owner 才能调用
        // 函数末尾加上 onlyOwner 声明,onlyOwner 正是上面定义的 modifier
        function transferOwnership(address newOwner) public onlyOwner{
            require(newOwner != address(0));
            emit OwnershipTransferred(owner, newOwner);
            owner = newOwner;
        }

    }
  • 上述合约的 transferOwnership 函数用于 owner 将所有权转让给其他人
    • 于是在末尾声明 onlyOwner 修改器,onlyOwner 将在 transferOwnership 执行前,先执行
require(msg.sender == owner);
  • 以保证此函数的调用者为 owner,如果不是 owner 则抛出异常

函数重载

  • 函数重载,是指同一个作用域内,相同函数名可以定义多个函数
  • 这些函数的参数(参数类型或参数数量)必须不一样,仅仅是返回值不一样是不被允许的
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test{
    function getSum(uint a,uint b)public pure returns(uint){
        return a+b;
    }
    function getSum(uint a, uint b,uint c)public pure returns(uint){
        return a+b+c;
    }
    function callSumWithTwoArguments() public pure returns(uint){
        return getSum(1, 2);
    }
    function callSumWithThreeArguments() public pure returns(uint) {
        return getSum(1, 2, 3);
    }
}

/*  首先单击 callSumWithTwoArguments 按钮,然后单击 callSumWithThreeArguments 按钮查看结果 */

数学函数

  • addmod(uint x,uint y,uint k) returns (uint),计算(x+y)%k
    • 计算中,以任意精度执行假发,且不限于 2^256 大小
  • mulmod(uint x,uint y,uint k) returns (uint),计算(x+y)%k
    • 计算中,以任意精度执行惩罚,且不限于 2^256 大小
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test{
    function callAddMod() public pure returns(uint){
        return addmod(4, 5, 3);
    }

    function callMulMod() public pure returns(uint){
        return mulmod(4, 5, 3);
    }
}

/*  首先单击callAddMod 按钮,然后单击 callMulMod 按钮查看结果 */

加密函数

  • kecckak256 (bytes memory) returns (bytes32) 计算输入的 Keccak-256 散列

  • sha256(bytes memory) returns (bytes32) 计算输入的SHA-256散列。

  • ripemd160(bytes memory) returns (bytes20) 计算输入的RIPEMD-160散列。

  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)

    • 从椭圆曲线签名中恢复与公钥相关的地址,或在出错时返回零

    • 函数参数对应于签名的 ECDSA 值:

      • r- 签名的前32字节

      • s- 签名的第二个32字节

      • v 签名的最后一个字节

    • 这个方法返回一个地址

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Test{
    function callKeccak256() public pure returns(bytes32 result){
        return keccak256("ABC");
    }
}

// 输出:0: bytes32: result 0xe1629b9dda060bb30c7908346f6af189c16773fa148d3366701fbaa35d54f3c8

猜你喜欢

转载自blog.csdn.net/BingjieDreams/article/details/130873818