solidity函数相关总结

function () {private|internal|external|public} [pure|constant|view|payable] [returns()]

  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";
    }
}

  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函数相关总结)