美文网首页
solidity函数相关总结

solidity函数相关总结

作者: 攻城老狮 | 来源:发表于2020-07-25 14:20 被阅读0次

    function (<parameter types>) {private|internal|external|public} [pure|constant|view|payable] [returns(<return types>)]

    1. 函数重载
      • 函数重载是指函数命名相同,但需要满足以下两个条件:
        • 函数传入参数的数量不同
        • 函数传入参数的类型不同
      • 若函数与多个参数均可以匹配,则会报错。例如 uint8 和 uint 均匹配时,报错
      • 返回值的不同无效,其不能作为重载的依据
      • address与uint160实际存储一致,故也会报错
    pragma solidity ^0.4.17;
    
    contract Overload{
        //error,重名方法
        function fun1(){}
        function fun1(){}
        //error,返回值不能作为判断依据
        function fun2() returns(string){}
        function fun2() returns(uint){}
        //参数数量的不同可以作为重载的依据
        function fun3(uint _num) {}
        function fun3() {}
        //编译通过,参数类型不同可以作为重载的依据,但是传参<256时会报错,无法匹配方法
        function fun4(uint _num) {}
        function fun4(uint8 _num) {}
        //编译通过,但两者存储方式一致,故无法匹配。但自己实际的版本时候可行需要进一步验证。
        function fun5(uint160 account) {}
        function fun5(address account) {}
    }
    
    1. 函数传入参数
      • 可以使用类json的格式传入参数,顺序可以调整
      • 在方法中调用其他方法时,必须传入所有参数,否则报错。但在外部调用多参数方法时,可以不必指定全部参数
    pragma solidity ^0.4.17;
    
    contract FuncParam{
        uint public num;
        string public name;
        //在外部调用该多参数方法时,参数可以不全部指定
        function setParam(uint _num,string _name) public{
            num = _num;
            name = _name;
        }
        //普通调用
        function test1() public{
            setParam(10,"yorick");
        }
        //使用类json的形式调用
        function test2() public{
            setParam({_name:"tom",_num:20});
        }
        //error,在方法中必须指定全部参数
        function test3() public{
            setParam(10);
        }
    }
    
    1. 函数参数返回
      • solidity支持多参数返回,采用元组的形式
      • returns中不是仅可以加类型,也可以添加变量。可以为该变量直接赋值。也可以通过return赋值。若两种方式都使用时,以return为标准。
    pragma solidity ^0.4.17;
    
    contract FuncReturn{
        //returns后可以写变量名
        function test1() pure public returns(uint a){
            uint num = 10;
            return num;
        }
        //可以为returns后面的变量直接赋值
        function test2() pure public returns(uint a){
            a = 20;
        }
        //两种赋值方式均存在的时候,以return为标准
        function test3() pure public returns(uint a){
            uint num = 10;
            a = 20;
            return num;
        }
        //多参数返回
        function test4() pure public returns(uint a,uint b){
            a = 10;
            b = 20;
        }
        //多参数return返回
        function test5() pure public returns(uint a,uint b){
            return (10,20);
        }
        function test6(uint num1,uint num2) pure public returns(uint add,uint mul){
            add = num1 + num2;
            mul = num1 * num2;
        }
        function test7(uint num1,uint num2) pure public returns(uint add,uint mul){
            return (num1+num2,num1*num2);
        }
    }
    
    1. 变量作用域
    pragma solidity ^0.4.17;
    
    contract ValueScope{
        uint public num = 100;
        //不能重定义
        //uint num = 200;
        //方法内部的重名变量覆盖了合约变量
        function test1() pure public returns(uint) {
            uint num = 10;
            num = 11;
            return num;
        }
        //传入的参数也属于方法内部的变量,故也覆盖了合约的重名变量
        function test2(uint num) pure public returns(uint){
            //以下均重定义 error
            //uint num = 13;
            //for(uint num=0 ; num<10 ; num++){}
            {
                //uint num = 10;
            }
            num = 12;
            return num;
        }
    }
    
    1. 值传递
    pragma solidity ^0.4.17;
    
    contract ValueTransfer{
        uint public num1 = 100;
        //仅是拷贝num1中的值
        uint public num2 = num1;
        //由于是值的传递,修改num2的值不会改变num1的值
        function changeNum() public{
            num2 = 999;
        }
        
        //参数传递拷贝的是副本,副本的修改与原数据无关
        function changeNum(uint _num2) pure public returns(uint){
            _num2++;
            return _num2;
        }
        function test() view public returns(uint){
            return changeNum(num2);
        }
    }
    
    1. constant关键字

      • constant可以在函数声明的时候使用,相当于view,不消化gas。但是5.0以后废弃
      • constant只能用于全局变量
      • constant声明的值不可以修改
      • constant可以用于uint,int,bytes,string类型的变量
    2. 构造函数

      • 构造函数会在合约部署时自动调用一次
      • 可以有很多用途,比如:初始化合约时候指定合约的拥有者
    pragma solidity ^0.4.17;
    
    contract FuncConstructor{
        uint public a;
        uint public b;
       //构造函数初始化合约变量的值
        constructor(uint _a,uint _b) public{
            a = _a;
            b = _b;
        }
    }
    
    //同一个文件可以写多个合约,部署时候选择对应合约即可
    contract FuncConstructor2{
         address public owner;
         //使用构造函数指定合约的拥有者地址
         constructor() public{
            owner = msg.sender;
        }
    }
    
    1. modifier函数
      • 调用modifier函数后会将调用方法的代码插入到 _; 位置运行,并且在其前后插入modifier函数已经写好的代码
      • 可以实现判断,赋值等操作
    pragma solidity ^0.4.17;
    
    contract ModifierTest{
        address public owner;
        uint public num;
        
        constructor() public{
            owner = msg.sender;
        }
        
        modifier OnlyOwner{
            //判断 地址是否为合约拥有者的地址
            require(msg.sender == owner);
            //将调用方法的代码动态插入
            _;
        }
        //使用modifier函数,仅需在后面添加该函数即可
        function changeNum() OnlyOwner public {
            num = 100;
        }
    }
    
    //功能:实现仅当没有注册该地址的时候才会执行注册操作
    //利用modifier做注册用户的判断操作
    contract ModifierTest2{
        mapping(address => uint) addressMapping;
        mapping(uint => string) idMapping;
        uint public count;
        
        //在注册前先判断是否已经将该地址注册进合约中
        modifier controlAddr{
            require(addressMapping[msg.sender] == 0);
            _;
        }
        //添加modifier函数的修饰
        function register(string name) controlAddr public{
            addressMapping[msg.sender] = ++count;
            idMapping[count] = name;
        } 
        function getId(address account) view public returns(uint){
            return addressMapping[account];
        }
        function getName(uint id) view public returns(string){
            return idMapping[id];
        }
    }
    
    //功能:仅当目前level超过needLevel时,才会执行方法的内容
    //利用带参数的modifier函数实现复杂控制
    contract ModifierTest3{
        uint public level = 5;
        uint public normalSkill;
        uint public superSkill;
        
        modifier controlSkill(uint needLevel){
            require(level >= needLevel);
            _;
        }
        //向modifier函数传递参数
        function changeNormalSkill() public controlSkill(2) {
            normalSkill = 10;
        }
        //向modifier函数传递参数
        function changeSuperSkill() public controlSkill(10) {
            superSkill = 20;
        }
    }
    
    //多重modifier的执行顺序,是嵌套的关系
    //本例中,相当于mod1嵌套了mod2,即:mod1(mod2)
    //执行顺序: num=1,num=3,num=100,num=4,num=2,最终num=2
    contract ModifierTest4{
        uint public num = 0;
        modifier mod1{
            num = 1;
            _;
            num = 2;
        }
        modifier mod2{
            num = 3;
            _;
            num = 4;
        }
        function test() mod1 mod2 public {
            num = 100;
        }
    }
    
    1. 合约继承
      • 合约通过 is 关键字来继承上一个合约
      • 合约可以连续继承,即:
        • b is a,表示b继承了a
        • c is b,表示c继承了b,同时也间接继承了a
    pragma solidity ^0.4.17;
    
    contract grandfater {
        uint public house = 3;
        function drink() pure public returns(string){
            return "drink";
        }
    }
    
    contract father is grandfater{
        uint public money = 10000;
        function learningSkill() pure public returns(string) {
            return "learning skill";
        }
    }
    
    contract son is father{
        function getMoney() view public returns(uint){
            return money;
        }
        function testLearningSkill() pure public returns(string){
            return learningSkill();
        }
        function testDrink() pure public returns(string){
            return drink();
        }
    }
    
    1. 修饰符权限
      • 不同说明:
        • internal只能在合约内部或者被继承的合约调用,合约外部不行
        • external只能在合约外部调用,合约内部或者被继承的合约不行。若一定要在合约内部调用external修饰函数有两种方法:
          • 可以使用this.函数名的方法在合约内部调用(this.函数名相当于通过合约地址调用该方法,类似于外部调用)
          • 再声明一个合约,在新的合约内部创建或者引用该合约即可
        • public合约内部,合约外部均可以调用
      • private不能够被继承,在合约外部不能被调用,但是在合约内部可以被调用
      • 什么是合约内部/外部?
        • 在内部就是指合约内部可以调用这个函数
        • 在外部就是指合约部署之后可以在旁侧看到这个函数的按钮
    是否继承 变量 函数
    public,internal public,internal,external
    private,external(变量实际没有external修饰符) private
    pragma solidity ^0.4.17;
    
    contract father{
        //属性的不同权限修饰
        uint a = 1;
        uint public b = 2;
        uint internal c = 3;
        uint private d = 4;
        //uint external e = 5;
        
        //方法的不同权限修饰
        function privateTest() pure private returns(string){
            return "private";
        }
        function publicTest() pure public returns(string){
            return "public";
        }
        function internalTest() pure internal returns(string){
            return "internal";
        }
        function externalTest() pure external returns(string){
            return "external";
        }
        
    }
    
    contract son is father{
        //在被继承的合约中,只能访问到public,internal和未设置,三类的属性值
        function showa() view public returns(uint){
            return a;
        } 
        function showb() view public returns(uint){
            return b;
        }
        function showc() view public returns(uint){
            return c;
        }
        //私有属性无法访问
        //function showd() view public returns(uint){
        //    return d;
        //}
        
        //在被继承的合约中,只能访问到public,internal以及使用this.函数名的external权限修饰的方法,而私有的方法无法访问
        function getPublic() pure public returns(string){
            return publicTest();
        }
        function getInternal() pure public returns(string){
            return internalTest();
        }
        function getExternal() view public returns(string){
            //error
            //return externalTest();
            return this.externalTest();
        }
        //私有方法无法访问
        //function getPrivate() view public returns(string){
        //    return privateTest();
        //}
    }
    
    //另外一种在合约内访问external修饰的方法
    contract newExternal{
        function getExternal() public returns(string){
            father f = new father();
            return f.externalTest();
        }
    }
    
    1. getter函数
      • 如果在声明变量时使用public方法,那么合约会自动生成一个external类型的函数,返回值是public声明的值的类型,命名就是变量名。如果是mapping还会需要一个参数
      • 如果我们在外面定义了这个函数,那么这个public变量自动生成的函数会自动消失
    pragma solidity ^0.4.17;
    
    contract Getter{
        //自动生成对应的getter方法
        uint public num = 233;
        //mapping类型会生成一个带参数key的getter方法,可以通过该key参数获取对应的value
        mapping(uint => string) public map;
        //mapping的复杂定义,一个mapping映射到另一个mapping
        mapping(uint => mapping(uint => string)) public complaxMap;
        
        //向map中设置一个键值对
        function setMapping() public {
            map[2] = "yorick";
        }
        //向复杂map中设置一个键值对
        function setComplaxMap() public {
            complaxMap[1][3] = "hello world";
        }
    }
    

    <img src="img/微信截图_20200519173528.png" style="zoom: 67%;" />

    1. 函数的重写
    pragma solidity ^0.4.17;
    
    contract Father{
        uint public money = 233;
        
        function learningSkill() pure public returns(string){
            return "learning C/C++";
        }
    }
    
    contract Son is Father{
        //重写父类中的属性
        uint public money = 666;
        //重写父类中的方法
        function learningSkill() pure public returns(string){
            return "learning solidity";
        }
        //测试是否重写成功,成功则会返回子类的属性和方法返回值
        function getContent() view public returns(uint,string){
            return (money,learningSkill());
        }
    }
    
    1. 多重继承
    pragma solidity ^0.4.17;
    
    contract Father{
        uint public height = 180;
        
        function learningSkill() pure public returns(string){
            return "learning C/C++";
        }
    }
    
    contract Mother{
        uint public height = 160;
        
        function learningSkill() pure public returns(string){
            return "learning Java";
        }
    }
    
    //继承了两个合约,若两个合约具有相同属性或方法时,子合约继承最后一个合约的内容。
    //若子合约定义同名属性或方法则覆盖父合约
    contract Son is Father,Mother{
        
    }
    
    1. 合约销毁
      • 函数通过selfdistrust(合约调用者地址,实际上就是msg.sender)
      • 销毁了合约之后,合约内的函数就会失效,无法再被调用
    pragma solidity ^0.4.17;
    
    contract DestructTest{
        address owner;
        uint public money;
        
        constructor() public{
            owner = msg.sender;
        }
        
        function increment() public{ 
            money += 10;
        }
        
        function killContract() public{
            if(msg.sender == owner){
                selfdestruct(msg.sender);
            }
        }
    
    }
    

    函数总结:

    • private,不能被继承,不能在外部调用,可以在内部调用

    • internal,可以被继承,不能在外部调用,可以在内部调用

    • external,可以被继承,只能在外部调用,不能在内部调用(若需要强制调用,通过 "地址.")

    • public,权限最大,均可

    • pure,不会读取全局变量,也不会修改全局变量,不消耗gas

    • view,只读取全局变量的值,不修改,不消耗gas

    • constant,在函数上与view相同;在全局变量中,表示不能够修改该修饰的变量

    • payable,转账时候必须加的关键字,表示可以支付的

    • 函数可以有多个返回值

    相关文章

      网友评论

          本文标题:solidity函数相关总结

          本文链接:https://www.haomeiwen.com/subject/nkaplktx.html