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只需要學習它與其他語言不同的地方
-
第一行的prama,是solidity的編譯控制指令,那我們這行代碼的意思是,源文件不允許被0.4.16以下,以及大於等於0.5.0版本的編譯器所編譯,簡單來說,允許的範圍就是左閉右開
0.4.16<=編譯器版本<0.5.0
在此區間的編譯器版本是可以編譯的。
-
contract關鍵字,相當於java中的class,定義一個合約
-
view關鍵字,這個是Solidity特有的關鍵字,因爲solidity最終是用在合約上,所以會有相關的功能,而view就是這些功能的其中一個,view只能用來修飾方法,而被修飾的方法不能修改狀態變量,也就是在java中的類的屬性,在這裏這個狀態變量就是Myname,在這裏我們可以看到getName()方法並沒有修改Myname的值
-
運行這個代碼,我們先調用getName函數,結果如下這張圖片顯示運行結果,運行成功
這張圖片顯示油費消耗,記住這個數字 -
運行setName()方法,這個方法需要傳入一個參數,我們在這裏傳入"李四",點擊運行,之後再運行getName()重新獲取值,結果如下
但是我們發現油費改變了,這說明了什麼? -
當我們繼續點擊getName()運行多次的時候,油費依舊不變,而當我們再次運行setName()方法的時候油費又會改變。
-
這說明了被view修飾的方法不會消耗油費,因爲它不需要改變狀態變量,所以view關鍵字還有節約油費的作用
-
pure關鍵字,被這個關鍵字修飾的方法不允許訪問狀態變量,所以也不需要花費油費。
-
bool,&& ,||,用法與java中完全一致,在這裏不過多解釋。
-
uint關鍵字,代表非負整型,默認是uint256,256是指256個比特位,
8bit=1byte
- solidity中也支持方法重載
- 位運算符:由於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.整數溢出以及異常處理
- 接下來我們要介紹非常危險的整數溢出問題,附上代碼。
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,可以驗證我們剛剛的結論是正確的。
- 我們再寫一個函數,附上代碼:
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屬性不可修改
}
}
- 字節數組雖然在存儲上與int一致,但是不能直接進行加減乘除操作。但是可以進行數的比較(>,>=,==,<=,<),也可以進行位運算(&, |, ~, ^, <<, >>)。
- 當屬性添加public後,會被默認生成一個獲取該屬性的get方法。
- 加上以下代碼,驗證上述說法,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;
}
}
-
運行initName之後,再查看name屬性的值:
結果沒問題 -
運行getLength()方法查看bytes數組的長度:
長度是2,結果正確
- 運行changeLength()方法修改bytes數組的長度:
長度變成了5
總結:動態字節數組能夠修改數組的長度。
- name.push(0x99)向name動態字節數組中添加一個0x99的元素。
4.string類型
- 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];
}
}
- 獲取name:
- 獲取長度爲8個字節:
- 調用getCName()獲取第一個字母:
6.調用changeName修改第一個字母之後再獲取name: