Solidity 从入门到实战(五)
注意:本专栏主要参考于https://www.bilibili.com/video/BV1St411a7Pk?p=11&spm_id_from=pageDriver的学习笔记以及https://blog.csdn.net/weixin_45067603/article/details/105751748
构造函数
- 在合约部署时自动调用一次,而且只能调用这一次
- 使用方法有两种:
①新式(推荐):constructor(参数列表) {}
②旧式:function 合约名(参数列表) {}
如果传入参数,那么部署时也需要输入参数- 作用:可以用来声明,赋值变量(常用于获取合约调用者的地址)等等
- 一个程序中可以写多个合约
//这里使用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
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();}}
注意:
- internal只能在合约内部调用,合约外部不行;
- 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函数的效果呢?有两种方式,本质上是通过间接通过外部合约调用
- 使用 this.函数名 调用
- 再声明一个合约,在新的合约内部创建或者引用该合约即可
//要想达到老师说的效果,选择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();}
}
函数小结
- private不能够被继承、不能够在外部调用、可以在内部被调用;
- internal 可以在内部被调用,不能在外部调用、可以被继承;
- external 不能在内部调用,只能在外部调用,如果强行调用,通过"地址."方式调用;
- public权限最大,可以在外部和内部调用,可以被继承;
- pure 不会读取全局变量,更不会修改全局变量,一个固定的输入就会有一个固定的输出,不消耗gas;
- constant 在函数中,与view相同,在全局变量中,只用于byte1–byte32,uint,int,string代表数据不能够被修改;
- view 只读取全局变量的值,不修改值,不消耗gas;
- payable 转账的时候必须要加的关键字
- 函数可以有多个返回值
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);}}
}