1. 程式人生 > >Solidity值型別與各種圖解

Solidity值型別與各種圖解

區塊鏈中級.以太坊開發
From:JamesZou & 傳智播客研究院 & 傳智播客區塊鏈

本文參考文件官方中文文件官方英文文件

一.值型別和引用型別

1.值型別

  • 值型別 是指變數在賦值過程中是將資料完整的拷貝一份,再賦值給新的變數,這種方式需要開闢新的記憶體空間,效率較低,兩個變數完全獨立,修改一個不會影響另外一個。
    • 布林(Booleans)
    • 整型(Integer)
    • 地址(Address)
    • 定長位元組陣列(fixed byte arrays)
    • 有理數和整型(Rational and Integer Literals,String literals)
    • 列舉型別(Enums)
    • 函式(Function Types)

思考:下面這個程式碼中的 luckNum 最後等於多少?

pragma solidity ^0.4.25;
contract ValueType{
    function testValueType() public view returns(uint){
        uint luckNum = 101;
        uint loveNum = luckNum;
        changeValue(luckNum);
        return luckNum;
} function changeValue(uint _num) private{ _num += 100; } }

在這裡插入圖片描述

2.引用型別

  • solidity沒有指標,對於複雜的結構進行高效傳遞方式是使用關鍵字storage進行修飾。
  • 複雜型別,佔用空間較大的。在拷貝時佔用空間較大。所以考慮通過引用傳遞。常見的引用型別有:
    • 字串(string)
    • 不定長位元組陣列(bytes)
    • 陣列(Array)
    • 結構體(Structs)

二.資料型別

1.值型別詳介

1.1 布林

bool flag1 = true;
bool flag2 = false;

1.2 整型

  • int(有符號整型,有正有負)

  • uint(無符號整型,無負數)

  • 以8位為區間,支援int8,int16,int24 至 int256,uint同理。

    int預設為int256,uint預設為uint256

function intTest() public  returns(int){
	int8 i = 10; 
	int j = 10; 

	return i + j;
}  

1.3 地址

1.3.1 概念
  • 以太坊地址的長度,大小20個位元組,每個位元組8位,20 * 8 = 160位,所以可以用一個uint160編碼。地址是所有合約的基礎,所有的合約都會繼承地址物件,通過合約的地址串,呼叫合約內的函式。
1.3.2 運算子
描述 符號
比較運算子 <=,<,==,!=,>=,>
1.3.3 操作
屬性/方法 含義 備註
balance(uint256) 獲取餘額(wei) 屬性,其餘的都是方法
transfer(uint256 value) 給 address 轉賬 value(Wei),失敗會拋異常 建議使用
send(uint256 value) 和 transfer 類似,transfer 更常用,失敗會返回false 不建議使用
call 合約內部呼叫合約
delegatecall 調底層程式碼,別用
callcode 調底層程式碼,別用

在這裡插入圖片描述

  • call 是一個底層的介面,用來向一個合約傳送訊息,也就是說如果你想實現自己的訊息傳遞,可以使用這個函式。函式支援傳入任意型別的任意引數,並將引數打包成32位元組,相互拼接後向合約傳送這段資料。
pragma solidity ^0.4.25;
contract Lover{
    string outerMsg;
    function(){
        outerMsg = string(msg.data);
    }
    function getFail() returns (string){
        return outerMsg;
    }
}
contract CallLover{
    function callData(address addr) returns (bool){
        return addr.call("i love Ether ~~!");
    }
}
  • call與delegatecall的功能類似,區別僅在於後者僅使用給定地址的程式碼,其它資訊則使用當前合約(如儲存,餘額等等)

注意:在 solidity 原始碼中,address 不需要加雙引號。但在 Remix 的對話介面中輸入 address 時,務必加上雙引號,否則會報錯

1.3.4 餘額
  • 返回指定地址的餘額
pragma solidity ^0.4.25;

contract addressTest{
   function getBalance(address addr) constant public returns  (uint){
       return addr.balance;
   }
}	
  • 合約地址 (this)

    如果只是想返回當前合約賬戶的餘額,可以使用this指標,this表示合約自身的地址

pragma solidity ^0.4.0;

contract addressTest{
    function getBalance() constant public returns  (uint){
        //return addr.balance;
        return this.balance; // <<----此處使用this代替
    }
}
  • 轉賬(send,transfer)

    send和transfer函式提供了由合約向其他地址轉賬的功能。

對比項 send transfer 備註
引數 轉賬金額 轉賬金額 wei單位
返回值 true/false 無(出錯拋異常) transfer更安全
pragma solidity ^0.4.25;

contract TransferTest {
    function transfer123(address addr) payable {
    	addr.transfer(msg.value);
    }
}
  • call 方法 (略)

1.4 位元組陣列

1.4.1 定長位元組陣列
  • solidity內建了一些陣列的資料型別:(和go語言做一下對比, var [8] byte),完全只讀

    • bytes1, … ,bytes32,允許值以步長1遞增。
    • byte預設表示bytes1,byte是型別,bytes是型別,bytes1是內建陣列
    • bytes1只能儲存1個位元組,即8位的內容,bytes2最多隻能儲存2個位元組,即16位的內容。以此類推…
    • 長度可以讀取 length
    • 長度不可以修改
    • 可以通過下標訪問
    • 內容不可修改
  • 內建方法:length() -> 返回陣列長度

  • 儲存方式:16進位制ascii碼

pragma solidity ^0.4.25;

//bytes1
contract fixedArray {
    /*
    1. 長度可以讀取 length
    2. 長度不可以修改
    3. 可以通過下標訪問
    4. 內容不可修改   
    */
    //bytes1 ... bytes32
    
    //bytes1 b1 = "xy";
    bytes2 b2 = "xy";
    
    bytes3 public b3 = "xy";
    
    uint public len = b3.length;
    
    //b3.length = 10;
    
    bytes8 b8 = "12345678";
    
    //b8_0返回0x31,即十進位制的數字1的ascii值(3*16+1=49)
    bytes1 public b8_0 = b8[0];
    
    //b = "HELLO";ERROR,定義之後不可修改
    //b8[1] = "0";
    //b8= "4567";
}
  • 運算子支援
描述 符號
比較運算 <=,<,==,!=,>=,>
位運算子 &,|,^(異或),~非
下標訪問 [0,n),n表示長度
1.4.2 不定長位元組陣列
  • bytes:不定長度的位元組陣列 (Dynamically-sized byte array)

    bytes型別可以使用 push() 方法,具有 length 屬性

string public name = "itheima.com";
bytes public g = 0x6c697975656368756e;
// 初始化一個兩個位元組空間的位元組陣列
bytes public name = new bytes(2);
  • string: 動態長度的UTF-8編碼的字元型別(非值型別),它其實是一個特殊的可變位元組陣列
string public str01 = "itheima.com";
  • solidity中字串不像JS中那樣,沒有length()方法,須轉換成位元組陣列才能使用length屬性來獲得長度
function getStrLegnth(string _str) constant returns (uint) {
	return bytes(_str).length;  // 強制轉換string為bytes
}
  • 一個好的使用原則是:
    bytes用來儲存任意長度的位元組資料,string用來儲存任意長度的UTF-8編碼 的字串資料。
    如果長度可以確定,儘量使用定長的如byte1到byte32中的一個,因為這樣更省空間。

1.5 列舉型別

  • 列舉型別是在Solidity中的一種使用者自定義型別。
  • 列舉可以顯示的轉換與整數進行轉換,但不能進行隱式轉換。顯示的轉換會在執行時檢查數值範圍,如果不匹配,將會引起異常。
  • 列舉型別應至少有一名成員,列舉元素預設為uint8,當元素數量足夠多時,會自動變為uint16,第一個元素預設為0,使用超出範圍的數值時會報錯。
pragma solidity ^0.4.0;

contract test {
   
    enum WeekDays {
        Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
    }
    
    WeekDays currentDay;
    WeekDays defaultday = WeekDays.Sunday;
    
    function setDay(weekDays _day) public {
        currentDay = _day;
    }
    
    function getDay() public view returns(uint256) {
        return uint256(currentDay);
    }
    
    function getDefaultDay() public view returns(uint256) {
        return uint256(defaultday);   
    }
}

1.6 函式型別

1.6.1 函式修飾符
  • 函式型別也就是我們所說的函式,本身也是一個特殊的變數,它可以當做變數賦值當做函式引數傳遞當做返回值

在這裡插入圖片描述

修飾符 說明
public 公有,任何人(擁有以太坊賬戶的)都可以呼叫
private 私有, 只有智慧合約內部可以呼叫
external 僅合約外部可以呼叫,合約內部需使用this呼叫
internal 僅合約內部和繼承的合約可以呼叫
view/constant 函式會讀取但是不會修改任何contract的狀態變數
pure 函式不使用任何智慧合約的狀態變數
payable 呼叫函式需要付錢,錢付給了智慧合約的賬戶
returns 返回值函式宣告中使用

注意,所有在合約內的東西對外部的觀察者來說都是可見,將某些東西標記為private僅僅阻止了其它合約來進行訪問和修改,但並不能阻止其它人看到相關的資訊。

1.6.2 匿名函式
  • 一個合約可以有且只有一個匿名函式,此函式不能有引數,也不能有任何返回值,當我們企圖去執行一個合約上沒有的函式時,那麼合約就會執行這個匿名函式。

    當合約在只收到以太幣的時候,也會呼叫這個匿名函式,而且一般情況下會消耗很少的gas,所以當你接收到以太幣後,想要執行一些操作的話,你儘可以把你想要的操作寫到這個匿名函式裡,因為這樣做成本非常便宜。

//如果想向合約轉賬,在合約中新增如下函式即可
function() payable {
    //函式體什麼都不填
}

區塊連結口設計和呼叫介紹

在這裡插入圖片描述

POS挖礦機制

在這裡插入圖片描述

ERC20代幣的圖解

在這裡插入圖片描述

編譯原始碼

在這裡插入圖片描述

合約部署圖解

在這裡插入圖片描述

引用型別傳參和值型別傳參

在這裡插入圖片描述