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;
}
//定義modifer
modifier 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;
//定義modifer
modifier 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);
}
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/281322.html
標籤:區塊鏈



