Smart contract development based on Ethereum Solidity (function & inheritance)

Reference tutorial:[Practical] 1. Function overloading_bilibili_bilibili

1. Function overloading:

pragma solidity ^0.5.17;

contract overLoadTest
{
    
    //不带参数
    function test() public
    {
        
    }
    
    //带一个参数
    function test(address account) public
    {
        
    }
    
    //参数类型不同,虽然uint160可以和address直接转化,但仍然满足重载的条件 
    function test(uint160 account) public
    {
        
    }
    
    //参数个数不同
    function test(uint160 account,address otherAccount) public
    {
        
    }
    
    // 此函数会编译报错,因为重载不考虑函数的返回值类型是否相同
    // function test(address account) returns(address sender){
    //     return msg.sender;
    // }
   
   uint public result = 0; 
    
    function negativeExample1(uint id) public
    {
        result = 100; 
    }
    
    function negativeExample1(uint8 id) public
    {
        result = 200;
    }
    
    function test1() public
    {
        //negativeExample1(1);  该语句会报错,因为传入函数的参数1既符合uint又符合uint8,        solidity无法辨别调用哪一个函数
    }

    function negativeExample2(address account) public
    {
        result = 100;
    }
    
    function negativeExample2(uint160 account) public 
    {
        result = 200;
    }

    function test2() public
    {
        //negativeExample2(1);  该语句会报错,address本质上就是一个uint160的一串数字,solidity无法辨别调用哪一个函数
    }
}

When some behavior patterns are consistent, but the input parameters for this behavior are different, it constitutes overloading. The specific performance is as follows:

①The functions have the same name

②The parameters of the function are different (type, quantity)

③It has nothing to do with the return value of the function

2. Function named parameters:

pragma solidity ^0.5.17;

contract functionParamTest
{
    
   uint public id;
   string public name;
   
   function setParam(uint _id,string memory _name) public 
   {
       id = _id;
       name = _name;
   }
   
   function test() public
   {
       setParam(18,"xiaofang");  //正常地传参
   }
   
   function test2() public
   {
       setParam({_id:18,_name:"xiaofang"});  //通过形参名给函数传参
   }
   
   function test3() public
   {
       setParam({_name:"xiaofang",_id:18});  //顺序可以与定义函数参数时不同(在较多参数情况下命名参数对于代码的可读性有很好的提升)
   }  

   function test4() public
   {
       setParam(18);  //调用函数传参时不可缺少参数,否则编译会报错(在外部调用函数时可以缺少参数,但不建议缺少)
   }
}

3. Characteristics of function return value:

pragma solidity ^0.5.17;

contract functionReturnTest
{
    
    //最常规的返回值写法  
    function test() public view returns(uint)
    {
        return 10;
    }

    //返回值也可以进行一个命名,在returns后可以声明返回值的名称
    function test1() public view returns(uint result)
    {
        result = 1;
        return result;  //如果不写这条语句也是可以的,因为有声明过返回值的名称(但不建议搞花里胡哨)
    }
    
    //可以返回任意匹配类型的值(类型必须匹配,名称不匹配没关系)
    function test2() public view returns(uint result)
    { 
        uint a = 10;
        result = 100;
        return a;
    }
    
    //可以返回多个参数,在声明了返回值名称的情况下可以不用写return语句,但必须要给返回值赋值
    function test3(uint a,uint b) public view returns(uint add,uint multiply)
    {
        add = a+b;
        multiply = a*b;
    }
    
    //返回多个参数时return语句要加括号
    function test4(uint a,uint b) public view returns(uint add,uint  multiply)
    {
        return (a+b,a*b);
    }
    
    //可以利用多返回值的特性直接进行数据交换操作
    function test5(uint a,uint b) public view returns(uint _b, uint _a)
    {
        return (b,a);
    }
    
}

4. Life cycle and scope of variables:

(1) Scope: There are a lot of curly braces in the program. The variable is defined in which pair of curly braces, then what this pair of curly braces contains is the variable. Scope, a variable can be effectively used within its scope. (Note that the scope of function parameters is inside the function, although it does not seem to be defined inside the function body)

(2) Life cycle: The period from when a variable is allocated space to when the space is reclaimed is called the life cycle of the variable. The life cycle of a variable starts from the time it is defined. Start and end at the end of its scope (if no manual destruction is performed).

5. Value transfer and copy copy:

pragma solidity ^0.5.17;

contract transferValueTest
{
    
    uint public a = 200;
    uint public b = a;   //将a的值赋给b,但是a和b各自占有不同的空间
    
    function changIt() public
    {
        b = 400;  //改变b的值,并不影响a
    }
    
    //i作为形式参数,当调用该函数时,是将所传值的副本传入的,并不会改变所传引用的值,也就是说,对i做修改并不影响a的值
    function changeIt3(uint i) public returns(uint)
    {
        i++;
        return i++;
    }
    
    function test() public 
    {
        changeIt3(a);
    }
  
}

6. const static modification:

pragma solidity ^0.5.17;

contract constantTest
{
    // 在0.4版本中,constant等同于view,在0.5以上的版本中已经废弃
    /*
    function test() public constant returns(uint)
    {
        return 100;
    }
    */
}

7. Constructor:

pragma solidity ^0.5.17;

contract constructorTest
{
    //初始化结果为0
    uint public a;
    //构造函数的名称与合约名相同,在合约部署(或者被创建)的时候执行(0.5以下版本支持该种语法)
    /*
    function constructorTest()
    {
        a = 100;
    }
    */
            
    //一个合约内部不能有多个构造函数
    /*
    function constructorTest(uint _a,uint _b){
        a = _a;
    }
    */
    //在0.5以上版本中,solidity采用了关键字constructor来定义构造函数
    constructor() public
    {
        a = 100;
    }

    /*
    address public ower;
     
    function constructorTest()  在合约部署时,可以借助构造函数传递一些内容到合约内,例如部署合约的账户
    {
        ower = msg.sender;
    }
    */
}

8. Function modifier modifire:

(1) Basic usage:

pragma solidity ^0.5.17;

contract modifireTest
{
    address public ower;
    
    uint public num = 0;
    
    constructor() public
    {
        ower = msg.sender;
    }
    
    //定义一个函数修改器 
    modifier onlyOwer
    {
        require(msg.sender == ower);  //不符合条件时则抛出异常,停止执行下面的语句并回滚
        //修饰函数时,函数相当于被插入到'_;'位置,然后把onlyOwer当作函数执行
        _;
    }
    
    function changeIt(uint _num) public onlyOwer
    {
        num = _num;  //该例中只有部署该合约的账户才有权利调用这个函数,其它账户调用该函数将会报错
       //当然,“require(msg.sender == ower);”也可以直接写在该函数中,这样就不需要借助modifier
    }
    
}

Exception handling in Solidity:

①Solidity uses "state recovery exception" to handle exceptions. Such an exception will undo all changes to state in the current call (and all its subcalls) and return an error to the caller.

②The functions assert and require can be used to determine conditions and throw exceptions when the conditions are not met.

• assert() should generally only be used to test internal errors and check constants

• require() should be used to ensure that valid conditions are met, or to verify the return value of an external contract call

• revert() is used to throw an exception, it can mark an error and roll back the current call

(2) Application example 1:

pragma solidity ^0.5.17;

contract mappingTest
{
    //一个钱包地址对应一个个人身份id 
    mapping(address => uint) idMapping;
    //一个人的身份id地址对应一个人的姓名
    mapping(uint => string) nameMapping;
    uint id = 0;
    address public ower;

    //定义一个函数修改器 
    modifier onlyOwer
    {
        require(idMapping[msg.sender] == 0);  //判断调用函数的账户有没有绑定身份的记录,以免同一账户注册多个身份
        //修饰函数时,函数相当于被插入到'_;'位置,然后把onlyOwer当作函数执行
        _;
    }

    function register(string memory name) public onlyOwer //该函数模拟新账户绑定身份
    {
        address account = msg.sender;  //调用该函数的账户为需要绑定身份和生成id号的新账户
        id++;  //这里的id号应该是随机生成,总之每个调用该函数的账户都应该获得不同的id号
        //给账户分配一个id
        idMapping[account] = id;
        //再将个人id与个人姓名进行映射绑定
        nameMapping[id] = name; 
    }
    //根据账户地址获取id
    function getIdByAddress(address account) public view returns(uint)
    {
        return idMapping[account];
    }
    //根据id获取个人姓名
    function getNameById(uint id) public view returns(string memory)
    {
        return nameMapping[id];
    }

(3) Application example 2:

pragma solidity ^0.5.17;

contract modifireTest
{
    uint level = 200;
    uint money = 0;
    
    modifier modifyLevel(uint _inputLevel)  //函数修改器可以有参数,这样使用起来更加灵活
    {
        
        require(level >= _inputLevel, "Your level is not within the range!");
       //如不满足require中的条件,错误类型为Your level is not within the range
        _;
    }
    
    function addMoney() modifyLevel(50) public 
    {
        //require(level >= 50);  五十级以上才能调用该函数
        money = 100;
    }
    
    function recoverCash() modifyLevel(200) public 
    {
        //require(level >= 200);  两百级以上才能调用该函数
        money = 200;
    }
    
    function getMoney() public view returns(uint) 
    {
        return money;
    }
    
}

(4) Execution sequence of multiple Modifire:

pragma solidity ^0.5.17;

contract modifireTest4
{
    uint public a = 0;
    
    modifier mod1
    {
        a = 1;  //执行顺序——1(最先执行)
        
        _;
        
        a = 2;  //执行顺序——5(最后执行)
    }
    
    modifier mod2
    {
        a = 3;  //执行顺序——2
        
        _;
        
        a = 4;  //执行顺序——4
    }
    
    function test() public mod1 mod2  //调用该函数后,a的值为2
    {
        a = 100;  //执行顺序——3
    }
    
}

9. Inheritance of contract:

(1) Basic inheritance:

pragma solidity ^0.5.17;

contract Father
{
    uint money = 10000;
    
    function noSmoking() public view returns(string memory)
    {
        return "I'm not somking";
    }
}

contract Son is Father  //继承语法:contract 子类名称 is 父类名称1,父类名称2……
{
    function getMoney() public view returns(uint)
    {
        return money;  //子类继承了父类中的属性
}

    function test() public view returns(string memory)
    {
        return noSmoking();  //子类继承了父类中的函数
    }
}

(2) Continuous inheritance:

pragma solidity ^0.5.17;

contract GrandFather
{
    uint height = 170;
}

contract Father is GrandFather
{
    uint money = 10000;
    function getHeight() public view returns(uint)
    {
        return height;  //子类继承了父类中的属性
    }
}

contract Son is Father
{
    function getHeight() public view returns(uint)
    {
        return height;  //子类继承了父类的父类中的属性
    }
}

(3) Inherited permissions:

①Inheritance of contract attributes:

pragma solidity ^0.5.17;

contract Father
{

    uint private privateMoney = 2000;  //加上private标识的属性或函数不会被子类继承
    //其余情况下可以被继承
    //uint privateMoney = 2000;
    //uint public privateMoney = 2000;
    //uint internal privateMoney = 2000;
    
    //注意:external不能修饰属性,只修饰函数
    
    uint money = 10000;
    
    function noSmoking() public view returns(string memory)
    {
        return "I'm not somking";
    }
    
}

contract Son is Father
{
    
    function getMoney() public view returns(uint)
    {
        return money;  //正常“财产”可以被继承
}

    function getPrivateMoney() public view returns(uint)
    {
        //return privateMoney;  父类的私房钱子类无法继承
}

}

②Public modified parent class function:

pragma solidity ^0.5.17;

contract Father
{
    
    function noSmoking() public view returns(string memory)
    {
        return "I'm not somking";
    }
    
}

contract Son is Father
{
    
    function test() public view returns(string memory)
    {
        return noSmoking();  //子合约可以正常调用父类中public修饰的函数
    }
    
}

③Private modified parent class function:

pragma solidity ^0.5.17;

contract Father
{
    
    function noSmoking() private view returns(string memory)
    {
        return "I'm not somking";
    }
    
}

contract Son is Father
{
    
    function test() public view returns(string memory)
    {
        //return noSmoking();  子合约不可以调用父类中private修饰的函数
    }
    
}

④Internal modified parent class function:

pragma solidity ^0.5.17;

contract Father
{
    
    function noSmoking() internal pure returns(string memory)
    {
        return "I'm not somking";
}

    function test() public returns(string memory)
    {
        return noSmoking();  //被internal修饰的函数,只能在合约内部以及子合约中被调用,外部无法直接调用
    }
    
}

contract Son is Father
{

    function test2() public pure returns(string memory)
    {
        return noSmoking();  //子合约可以正常调用父类中internal修饰的函数(当然,也只能在合约内部调用,外部不可见)
    }
    
}

⑤external modified parent class function:

pragma solidity ^0.5.17;

contract Father
{
    
    function noSmoking() external pure returns(string memory)
    {
        return "I'm not somking";
    }

    function test() public returns(string memory)
    {
        //return noSmoking();  被external修饰的函数,只能在外部被调用,合约内部以及子合约中无法直接调用
        return this.noSmoking();  //通过this可以让编译器认为这是在外部通过该合约地址调用该函数,这样就不会报错
    }
    
}

contract Son is Father
{

    function test2() public view returns(string memory)  //使用this的话,千万不要使用pure
    {
        //return noSmoking();
        return this.noSmoking();  //子类也可以通过this调用父类中external修饰的函数
    }
    
}

contract Mother
{

    function test() public returns(string memory)
    {
        Father f = new Father();  //对于被external修饰的函数,在其它非子合约中可以直接创建合约对象,通过合约对象进行外部调用
        return f.noSmoking();
    }
    
}

10. Global variable automatic getter function:

(1) Get method of ordinary variables:

pragma solidity ^0.5.17;

contract GetterTest
{
    
    uint public num = 100;  //public修饰符修饰的属性,默认会生成一个get方法,供我们外部调用
    
    /*
    function num() external returns(uint)  
    {
       return num;
    }
    1、变量用public修饰后,这个函数就是生成的get方法(函数体内部定义的变量不能用public修饰)
    2、默认生成的get函数是external权限的,不能够在合约的内部调用
    3、对于该例,num()方法只能有一个,要是自己进行重写,就会覆盖默认生成的get方法
    */
    
     function test() public
     {
        // num();
        this.num();  //可以通过this对get方法进行外部调用
        
    }
    
}

(2) Get method of mapping type data:

pragma solidity ^0.4.18;  //编译器版本与前面例子所用的不同

contract GetterTest
{
    
mapping(uint => string) public map;

    function map(uint key) external returns(string)  //map的get方法(需传入key值才能获取value值,对于嵌套的mapping,就需要传入多个key值)
    {
        return map[key];
    }
    
}

Supplement - mapping mapping:

pragma solidity ^0.5.17;

contract mappingTest
{
    //个人认为这个有点像Python中的字典(可以理解为mapping(key => value) 字典名)
    //一个钱包地址对应一个个人身份id 
    mapping(address => uint) idMapping;
    //一个人的身份id地址对应一个人的姓名
    mapping(uint => string) nameMapping;
  
    uint id = 0;
    function register(string memory name) public //该函数模拟新账户绑定身份
    {
        address account = msg.sender;  //调用该函数的账户为需要绑定身份和生成id号的新账户
        id++;  //这里的id号应该是随机生成,总之每个调用该函数的账户都应该获得不同的id号
        //给账户分配一个id
        idMapping[account] = id;
        //再将个人id与个人姓名进行映射绑定
        nameMapping[id] = name;        
    }
    //根据账户地址获取id
    function getIdByAddress(address account) public view returns(uint)
    {
        return idMapping[account];
    }
    //根据id获取个人姓名
    function getNameById(uint id) public view returns(string memory)
    {
        return nameMapping[id];
}

    mapping(uint => mapping(uint => mapping(uint => string))) public map;
    function test() public
    {
        map[0][1][1] = "lalalalala";  //mapping数据类型还可以嵌套,相当于Python中的多维字典
        //map[0]:mapping(uint => mapping(uint => string))
        //map[0][1]:mapping(uint => string)
        //map[0][1][1]:string
    }
   
}

mapping(key => value) Related statements of Mapping:

(1) The function of "mapping(type1 => type2) Mapping;" is to create a mapping from type1 to type2, and the name of the mapping group is "Mapping".

(2) The function of "Mapping[key] = value;" is:

① If there is no key value of key in the Mapping group before, then the mapping of key value to value will be added to the Mapping group.

② If the key value key previously existed in the Mapping group, then the mapping of key key value is changed to value.

11. Rewriting in inheritance:

(1) Attribute rewriting:

pragma solidity ^0.5.17;

contract Father
{
    
   uint money = 10000;
   uint public height = 170;  //父类属性用public修饰,那么子类继承后会生成get方法,调用该方法会获取父类的height而不是子类的
    
}

contract Son is Father
{
    
    uint money = 20000;  //子类重写了父类的money,以子类为准(但是不影响父类的money)
    uint height = 180;  //子类重写了父类的height,那么子类使用height时将以此为准(如果用public修饰该属性,那么此处生成的get方法会将父类生成的get方法覆盖,调用该方法会获取子类的height)
    
    function getMoney() public view returns(uint)
    {
        return money;
    }

    function getHeight() public view returns(uint)
    {
        return height;
}

}

(2) Function rewriting:

pragma solidity ^0.5.17;

contract Father
{
   uint public money = 10000;
   
   function noSmoking() public view returns(string memory)
   {
       return "I don't smoke,and I do not drink";
   }
}

contract Son is Father
{
    uint public money = 20000;
    
    function noSmoking() public view returns(string memory)  //子类重写了父类的函数,父类函数将会被覆盖
    {
        return "I do not smoke,but I do drink";
    }
    
    function test() public view returns(string memory)
    {
        return noSmoking();
    }
}

12. Things you need to pay attention to when using multiple inheritance:

pragma solidity ^0.5.17;

contract Father
{
    
   uint public money = 10000;
   
   uint public height = 180;
    
}

contract Mother
{

    uint public money = 20000;
    
    uint public height  = 170;
    
    uint public weight = 120;
    
}

contract Son is Father,Mother
{
    function test() public view returns(uint)
    {
        return height;  //会返回Mother中的height,后继承的属性如果与前面继承的相同,前继承的属性将会被覆盖
    }
    
}

13. Destruction of contract (destructor):

pragma solidity ^0.5.17;

contract DestructTest
{
    
    address ower;
    
    constructor() public
    {
        ower = msg.sender;
    }

    uint public money = 100;
 
    function increment() public
    {
        money += 100;
    }
    
    function kill() public
    {
        if(msg.sender == ower)  //只有发布合约的账户有权利销毁合约
        {
            //手动进行自我销毁
            selfdestruct(msg.sender);
        }
    }    
}

Guess you like

Origin blog.csdn.net/Zevalin/article/details/134894111