Solidity學習(一)

1.Solidity基礎

友情提示:每一句話都非常重要,每一個點都是細節。再者本教程適合有一定編程基礎的小夥伴快速入門
基本語法,整數溢出以及異常處理,字節數組,動態字節數組,字符串,字符串與字節數組的相互轉換,幫助大家快速入門Solidity

這裏直接給一段代碼

pragma solidity ^0.4.16;

contract Helloworld {
    string Myname = "張三";
    function getName() public view returns(string) {
        return  Myname;
    }
    function setName(string newname) public {
        Myname = newname;
    }
     function pureTest(string _name) public pure returns (string) {
        return _name;
    }
}

這裏使用的編輯器是remix網頁編輯器:點擊進入remix編輯器

下面我們對這段代碼進行分析

在java中,已經有很多的小我們大致瞭解,所以我們學習solidity只需要學習它與其他語言不同的地方

  1. 第一行的prama,是solidity的編譯控制指令,那我們這行代碼的意思是,源文件不允許被0.4.16以下,以及大於等於0.5.0版本的編譯器所編譯,簡單來說,允許的範圍就是左閉右開

    0.4.16<=編譯器版本<0.5.0

    在此區間的編譯器版本是可以編譯的。

  2. contract關鍵字,相當於java中的class,定義一個合約

  3. view關鍵字,這個是Solidity特有的關鍵字,因爲solidity最終是用在合約上,所以會有相關的功能,而view就是這些功能的其中一個,view只能用來修飾方法,而被修飾的方法不能修改狀態變量,也就是在java中的類的屬性,在這裏這個狀態變量就是Myname,在這裏我們可以看到getName()方法並沒有修改Myname的值

  4. 運行這個代碼,我們先調用getName函數,結果如下Redmix代碼運行結果這張圖片顯示運行結果,運行成功
    油費1
    這張圖片顯示油費消耗,記住這個數字

  5. 運行setName()方法,這個方法需要傳入一個參數,我們在這裏傳入"李四",點擊運行,之後再運行getName()重新獲取值,結果如下
    在這裏插入圖片描述
    在這裏插入圖片描述
    但是我們發現油費改變了,這說明了什麼?


  6. 當我們繼續點擊getName()運行多次的時候,油費依舊不變,而當我們再次運行setName()方法的時候油費又會改變。

  7. 這說明了被view修飾的方法不會消耗油費,因爲它不需要改變狀態變量,所以view關鍵字還有節約油費的作用

  8. pure關鍵字,被這個關鍵字修飾的方法不允許訪問狀態變量,所以也不需要花費油費。

  9. bool,&& ,||,用法與java中完全一致,在這裏不過多解釋。

  10. uint關鍵字,代表非負整型,默認是uint256,256是指256個比特位,

8bit=1byte

  1. solidity中也支持方法重載
  2. 位運算符:由於solidity是用來部署合約,所以對內存要求很高,爲了節約內存,位運算符顯得相當重要

&:按位與,同時爲1,得到1,有一個及以上爲0,就是0
|:按位或,同時爲0,得到0,有一個及以上爲1,就是1
~:取反,0變成1,1變成0(只需要一串數字就可以)
^:按位異或,相同爲0,不相同爲1
<<:左移
.>>:右移




將上面的符號全部測試一遍,這裏不給出結果,有興趣的可以自己去運行一下


pragma solidity ^0.4.16;
   
   contract BoolTest {
       uint8 a = 4;
       uint8 b = 2;
       
       function plus() public view returns(uint8){
           return a + b;
       }
       function minus() public view returns(uint8){
           return a - b;
       }
       function multiply() public view returns(uint8){
           return a * b;
       }
       function divide() public view returns(uint8){
           return a / b;
       }
       function power() public view returns(uint8){
           return a ** b;
       }
       
       function test1() public view returns(uint8){
           return a&b;
       }
       function test2() public view returns(uint8){
           return a|b;
       }
       function test3() public view returns(uint8){
           return ~b;
       }
       function test4() public view returns(uint8){
           return a^b;
       }
       function test5() public view returns(uint8){
           return a<<1;
       }
        function test6() public view returns(uint8){
           return a>>1;
       }
   }

2.整數溢出以及異常處理

  1. 接下來我們要介紹非常危險的整數溢出問題,附上代碼。
 function flow() public pure returns(uint8){
           uint8 mm = 255;
           return mm;
       }

我們知道。8個比特位的數據範圍是0~255,所以這個方法會返回一個mm的值,是255,運行結果沒問題。在這裏插入圖片描述
接下來我們修改一下代碼,修改後的代碼在下方

function flow() public pure returns(uint8){
           uint8 mm = 255;
           mm++;
           return mm;
       }

代碼修改後,mm理應變成256,但是256已結超過了8個比特位的取值範圍,所以會出現錯誤。運行結果:
在這裏插入圖片描述
可以看到,mm的值輸出直接變成了0,爲什麼會有這種結果呢?

1 1 1 1 , 1 1 1 1

上面是我們的8個比特位,這個是255的二進制表示,當這個數加1的時候,最後一位加1,學過二進制的朋友都知道,依次從後往前滿2進1,最後的結果是:

1, 0 0 0 0, 0 0 0 0

由於我們只能讀取8個比特位,所以讀取之後的值就是

0 0 0 0, 0 0 0 0

這個值就是0,所以m後8位讀取變成了0。

爲了驗證我們的結論,我們再次修改代碼:

 function flow() public pure returns(uint8){
           uint8 mm = 255;
           mm++;
           mm++;
           return mm;
       }

運行結果:
在這裏插入圖片描述
可以看到,當我們讓mm在之前的基礎上再加1之後,變成了

0 0 0 0, 0 0 0 1

所以mm的結果就是1,可以驗證我們剛剛的結論是正確的。

  1. 我們再寫一個函數,附上代碼:
function erroTest() public pure returns(int){
            int a1 = 1;
            int a2 = 0;
            return a1/a2;
        }

注意觀察上面的函數,很明顯我們看到上面的函數發生了錯誤,因爲0不能做除數,那我們編譯這個代碼是能通過的,但是當我們調用這個函數的時候就會看到以下字段
在這裏插入圖片描述
這就是發生了一個異常。

注意:solidity目前不支持小數類型

3.字節數組

我們還是先給一段代碼

pragma solidity ^0.4.0;
 
 contract BytesArray {
     
     bytes1 public num1 = 0x7a;// 只有一個字節的數  二進制表示:0111 1010
     bytes2 public num2 = 0x7a68;// 有兩個字節的數 二進制表示:0111 1010 0110 1000
     
     function getLength() public returns(uint256) {
          return num1.length;// length屬性不可修改
     }
     
     function getLength2() public returns(uint256) {
          return num2.length;// length屬性不可修改
     }
 }
  1. 字節數組雖然在存儲上與int一致,但是不能直接進行加減乘除操作。但是可以進行數的比較(>,>=,==,<=,<),也可以進行位運算(&, |, ~, ^, <<, >>)。
  2. 當屬性添加public後,會被默認生成一個獲取該屬性的get方法。
  3. 加上以下代碼,驗證上述說法,f分別求&, |, ~, ^, <<, >>位運算後的值,並返回。
 function and() public returns(bytes2 n1,bytes2 n2,bytes2 n3, bytes2 n4, bytes2 n5,bytes2 n6){
          return (num1&num2,num1|num2,~num1,num1^num2,num1<<1,num1>>1);
      }

得到結果:
在這裏插入圖片描述
結果正確。

4.動態字節數組

上代碼:

 pragma solidity ^0.4.0;
 
 contract BytesArray {
     
     bytes public name = new bytes(2);
     
     function initName() public {
         name[0] = 0x7a;
         name[1] = 0x68;
     }
     
     function getLength() public returns(uint256){
         return name.length;
     }
     
     function changeLength() public {
         name.length = 5;
     }
 }
  1. 運行initName之後,再查看name屬性的值:
    在這裏插入圖片描述
    結果沒問題

  2. 運行getLength()方法查看bytes數組的長度:

在這裏插入圖片描述
長度是2,結果正確

  1. 運行changeLength()方法修改bytes數組的長度:
    在這裏插入圖片描述
    在這裏插入圖片描述
    長度變成了5


總結:動態字節數組能夠修改數組的長度。

  1. name.push(0x99)向name動態字節數組中添加一個0x99的元素。

4.string類型

  1. string操作與java基本一致,string餘額bytes之間可以強制轉換,這一特性可以用來訪問string中特定位置的值。
    代碼測試
pragma solidity ^0.4.0;

contract StringTest {
    string public name = "zhangsan";
    
    function getLength() public returns(uint256){
        return bytes(name).length;
    }
    
    function changeName() public {
        bytes(name)[0] = 'L';
    }
    
    function getCName() public returns(bytes1){
        return bytes(name)[0];
    }
}
  1. 獲取name:
    在這裏插入圖片描述
  2. 獲取長度爲8個字節:
    在這裏插入圖片描述
  3. 調用getCName()獲取第一個字母:
    在這裏插入圖片描述
    6.調用changeName修改第一個字母之後再獲取name:
    在這裏插入圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章