当前位置: 代码迷 >> 综合 >> Solidity 从入门到实战(五)
  详细解决方案

Solidity 从入门到实战(五)

热度:54   发布时间:2023-12-26 01:31:08.0

Solidity 从入门到实战(五)

注意:本专栏主要参考于https://www.bilibili.com/video/BV1St411a7Pk?p=11&spm_id_from=pageDriver的学习笔记以及https://blog.csdn.net/weixin_45067603/article/details/105751748

构造函数

  1. 在合约部署时自动调用一次,而且只能调用这一次
  2. 使用方法有两种:
    ①新式(推荐):constructor(参数列表) {}
    ②旧式:function 合约名(参数列表) {}
    如果传入参数,那么部署时也需要输入参数
  3. 作用:可以用来声明,赋值变量(常用于获取合约调用者的地址)等等
  4. 一个程序中可以写多个合约
//这里使用0.4.16版本会出现编译错误,因为构造函数与编译器版本不匹配出错,这里选择使用0.5.0
pragma solidity ^0.5.0;contract gouzao2Test{
    address public owner;uint public a;constructor() public{
    //a=100;owner = msg.sender;//获取合约调用者的地址}}
contract gouzaoTest{
    uint public a; //一个合约只能有零个或一个构造函数//构造函数在一部署合约的时候就回被执行//function gouzaoTest(){
    // a=100;//}//构造函数可以有参数// function gouzaoTest(uint _a,uint _b) {
    // a=_a;// }
}  

在这里插入图片描述

modifier函数

  1. 应用场景:作判断,赋值等等
  2. 主要作用:使得代码可以重用

案例1

pragma solidity ^0.5.0;contract modifierTest{
    address public owner;uint public num =0;constructor()public {
    //合约部署者的地址owner = msg.sender;}//定义modifermodifier OnlyOwner{
    //判断当前登录者地址是否是合约的部署者,如果是的话,执行下面的语句,否则,进行回滚操作require(msg.sender == owner);_;}//附加 modifer,先执行 require(msg.sender == owner),判断成功后,就会执行num = _num;function changeIt(uint  _num)public OnlyOwner {
    num = _num;}}   

当require(msg.sender == owner)判断成功的时候

在这里插入图片描述

当require(msg.sender == owner)判断不成功的时候
在这里插入图片描述

案例2

对之前一个注册的案例进行改造,因为存在一个账户可以重复注册多次的问题

pragma solidity ^0.4.16;
contract mappingTest{
    // 定义mapping idmapping 代表地址==》id映射到了一起,namemapping代表id==>名字映射到了一起mapping(address => uint) idmapping;mapping(uint => string) namemapping;//定义注册的总量uint public sum =0;//定义modifermodifier control{
    //如果当前idmapping[msg.sender]==0,说明该用户是个新用户,允许进行接下来的操作require(idmapping[msg.sender]==0);_;}//注册函数function register(string name) control{
    //获取当前合约的调用者地址address account = msg.sender;sum++;//将合约的调用者的地址与注册总量id联系到一起idmapping[account]= sum;//将当前用户的id与用户的姓名绑定到一起namemapping[sum] =name;}//通过地址获取到用户绑定的id值function getIdByAddress(address are) view public returns(uint){
    return idmapping[are];}//通过id值获取到它绑定的姓名function gerNameById(uint id) view public returns(string){
    return namemapping[id];}
}

新用户第一次注册
在这里插入图片描述
新用户再次注册
在这里插入图片描述

案例3

modifer可以有参数

pragma solidity ^0.4.16;
contract mappingTest2{
    uint public level =9;string public name;uint public DNA;//定义modifier,可以有参数,提高了代码的重用性和扩展性modifier contrlLevel(uint needLevel){
    require(level >= needLevel);_;}function changeName() contrlLevel(2){
    name ="吴彦祖";}function changeDNA() contrlLevel(10){
    DNA = 999;}
}

在这里插入图片描述

案例4

多个modifier的执行顺序

pragma solidity ^0.4.16;
contract mulmodifierTest{
    uint public a =0;modifier mod1{
    a=1;_; //将mod2嵌入进来a=2;}modifier mod2{
    a=3;_;a=4;}//执行顺序:a=1,a=3,a=100,a=4,a=2;function test() mod1 mod2{
    a=100;}
}

在这里插入图片描述

继承

无权限的继承

pragma solidity ^0.4.16;contract grandfarther{
    uint public gudong =2000;function zhongdi() public returns(string){
    return "zhongdi";}
}
contract father is grandfarther{
    uint public money =10000;function dahan() public returns(string){
    return  "dahan";}
}
//son继承了father,father继承了grandfarther,son就可以继承他们的所有属性和函数
contract son is father{
    function getMoney() public view returns(uint){
    return money;}function getGudong()public view returns(uint){
    return gudong;}function test01() public view returns(string){
    return zhongdi();}function test02() public view returns(string){
    return dahan();}
}

在这里插入图片描述

有权限的继承

pragma solidity ^0.4.16;
contract father {
    
//1. uint money=10000;不加任何修饰符,可以被继承
//2. uint public money=10000;加上public,可以被继承
//3. uint internal money=10000;加上internal,可以被继承
//4. uint external money=10000;编译报错,没有external属性修饰符uint private money =10000;//编译报错,只有父亲拥有改属性,不能被继承function dahan() public returns(string){
    return  "dahan";}
}contract son is father{
    function getMoney() public view returns(uint){
    return money;}}

函数继承

pragma solidity ^0.4.16;contract father {
    //public、internal、external 函数都可以被继承,external函数继承方式不太相同,如下面的代码所示//private智能合约自己独立使用,不能够被继承function dahan() public pure  returns(string){
    return  "dahan";}
}contract son is father{
    function test() public  pure returns(string){
    return dahan();}}
pragma solidity ^0.4.16;contract father {
    function dahan() external pure  returns(string){
    return  "dahan";}
}contract son is father{
    function test() public  pure returns(string){
    //external 函数继承方式this.dahan();}}

注意:

  1. internal只能在合约内部调用,合约外部不行;
  2. external只能在合约外部调用,合约内部不行;
    所谓外部和内部,以remix举例,在内部就是指合约内部可以调用这个函数,在外部就是指合约部署之后可以在旁侧看到这个函数的按钮。
    如下图所示,farther外部只显示test1(),但是可以调用dahan()这个函数。

在这里插入图片描述

如下图所示,external在合约内部按照下图所示方式调用会出现错误

pragma solidity ^0.4.16;contract father {
    function dahan() external pure  returns(string){
    return  "dahan";}//external修饰的函数不能够在内部调用
// function test1() public view {
    
// dahan();
// }
}contract son is father{
    //external修饰的函数不能够在被继承的合约内部调用function test() public  view returns(string){
    return dahan();}}

在这里插入图片描述

external能在合约外部调用

在这里插入图片描述

那么,如何达到合约内部调用external函数的效果呢?有两种方式,本质上是通过间接通过外部合约调用

  1. 使用 this.函数名 调用
  2. 再声明一个合约,在新的合约内部创建或者引用该合约即可
//要想达到老师说的效果,选择0.4.0版本,编译器选择0.4.23版本
pragma solidity ^0.4.0;contract father {
    function dahan() external pure  returns(string){
    return  "dahan";}//间接的在合约内部调用,输入this.function test1() public view  {
    this.dahan();}
}contract son is father{
    function test() public  view returns(string){
    this.dahan();}}

在这里插入图片描述

//要想达到老师说的效果,选择0.4.0版本,编译器选择0.4.23版本
pragma solidity ^0.4.0;contract father {
    function dahan() external  pure  returns(string){
    return  "dahan";}function test1() public view returns(string) {
    return  this.dahan();}
}// contract son is father{
    // function test() public view returns(string){
    
// this.dahan();
// }// }
//第二种调用方式,在另一个合约内部创建或引用合约的地址“地址.”来调用
contract externalTest {
    father f =new father();function externalTestIt() public view returns(string){
    return  f.dahan();}
}

在这里插入图片描述

函数小结

  1. private不能够被继承、不能够在外部调用、可以在内部被调用;
  2. internal 可以在内部被调用,不能在外部调用、可以被继承;
  3. external 不能在内部调用,只能在外部调用,如果强行调用,通过"地址."方式调用;
  4. public权限最大,可以在外部和内部调用,可以被继承;
  5. pure 不会读取全局变量,更不会修改全局变量,一个固定的输入就会有一个固定的输出,不消耗gas;
  6. constant 在函数中,与view相同,在全局变量中,只用于byte1–byte32,uint,int,string代表数据不能够被修改;
  7. view 只读取全局变量的值,不修改值,不消耗gas;
  8. payable 转账的时候必须要加的关键字
  9. 函数可以有多个返回值

getter使用

案例1

pragma solidity ^0.4.0;
//1.public修饰符默认生成get方法,供我们外部调用
contract getter{
    uint public num =100;//2.它等价于这个函数,当我们写了这个函数的时候,默认的函数就会消失//3. 默认生成的get函数是external权限的,不能够在合约的内部调用function num() external view returns(uint){
    return num;}function test(){
    this.num();}
}

在这里插入图片描述

案例2

pragma solidity ^0.4.0;contract getter{
    uint public num =100;mapping(uint =>string) public map;//mapping类型很特殊,默认的会生成下面这个函数,//function map(uint key)external returns(string){
    //}function test(){
    this.num();}function test2(){
    map[2] ="吴彦祖";}function test3()returns(string){
    return this.map(2);}
}

在这里插入图片描述

案例3

pragma solidity ^0.4.0;contract getter{
    mapping(uint =>mapping(uint =>mapping(uint =>string))) public map;function test(){
    map[0][1][2]= "吴彦祖";}}

在这里插入图片描述

继承函数的重写

pragma solidity ^0.4.0;contract father{
    uint public money =10000;function dahan() returns(string){
    return "打小鼾";}
}contract son is father {
    
//覆盖掉父亲的值uint public money =200000;function getMoney()returns(uint){
    return  money;}function dahan()returns(string){
    return "打大鼾";}function test() view returns(string){
    //覆盖掉父亲的方法return dahan();}
}

在这里插入图片描述

多重继承

pragma solidity ^0.4.0;contract father{
    uint public money =10000;function test() returns(string){
    return "A";}
}
contract mother{
    uint public heignt =180;function test()returns(string){
    return "B";}
}
contract son is father,mother {
     //按照father,monther的顺序进行继承uint public money =200000;uint public heignt =190; //重写属性值function test() returns(string){
     //重写方法return "son";}function getHeight() returns(uint){
    return heignt;}
}

在这里插入图片描述

合约销毁

pragma solidity ^0.4.0;contract destruct{
    address owner;uint public money =0;constructor(){
    owner = msg.sender;}function increment(){
    money +=10;}function kill(){
    if(msg.sender == owner){
    //如果是当前合约的调用者,进行销毁合约selfdestruct(owner);}}
}

在这里插入图片描述