1. 程式人生 > 其它 >Solidity語法知識點(文末有彩蛋)

Solidity語法知識點(文末有彩蛋)

最近報名參加了矽谷區塊鏈舉辦的《智慧合約開發課》第二期培訓班,根據培訓要求,不能透露課程的內容,但我會在steemit上不斷地記錄我的成長過程。

https://steemit.com/cn/@speeding/smart-contract-development0

單純地學Solidity的語法知識點非常枯燥,而放在一個個的實際例子中逐步深入時,則輕鬆了許多,當前已經學完了智慧合約開發課的第三課,必須抓緊把學過的語法點總結一下。

一、檔名

solidity檔案的副檔名為*.sol

二、指定編譯器版本

pragma solidity ^0.4.0;

表示源程式在大於等於0.4.0版本的編譯器可以正常工作,在大於等於0.5.0版本中的編譯器中無法工作。即:

0.4.0 <= version < 0.5.0

關於pragma的詳細文件在這裡:http://solidity.readthedocs.io/en/develop/layout-of-source-files.html#version-pragma

而版本號之前的“^”符號的含義,來自於npm中的語法 。

三、資料型別

solidity是靜態型別語言,所有變數需要有定義宣告。

1)整數

常用的無符號整數型別有uint8, uint16, uint24, ... ,uint256。256個位元組的無符號整數uint256可以簡寫為uint。而有符號的整數則從int8, int16一直到int256。

這些整數經常會用來儲存使用者的token數量,小心加、減、乘、除運算後的結果溢位,那可是非常慘痛的損失。

uint a = 365;

2)地址

address用來儲存以太坊的地址,實際上就是不超過20位元組的無符號整數,例如:

address a = 0xdd870fa1b7c4700f2bd7f44238821c26f7392148;

後面的0x開頭的一串十六進位制數並不是字串,不需要雙引號。而在remix除錯程式時,傳入的地址引數卻需要雙引號括起來,新手一開始經常會遇到這個錯誤。

地址有合約地址和普通的錢包地址兩種。

3)結構struct

與C語言非常相似,不用多說。

struct Participator {
    address addr;  
    uint amount;
}

4)陣列

Solidity支援定長陣列:

uint[5] a;

也支援動態陣列:

uint []b;

在動態陣列中增加一個元素用push()函式。

b.push(1);

b.push(2);

b.length得到陣列的長度,還可以直接修改length來刪除元素。

b.length = 1;

5)mapping型別

這種型別相當於其它語言中的雜湊表,一開始不太適應,是solidity中非常重要的一種資料型別,以後再展開。

6)var

var並不是表示動態型別,而是讓書寫更簡單,一個值在分配給var變數時,其型別就已經確定了。如果要賦值給其它型別,仍要進行強制型別轉換。

7)其它型別

solidity中還支援布林型別、字串型別、列舉型別等等。非常神奇,這次的培訓課中竟然一直沒講string型別,通常的程式語言都會在第一課介紹"hello world"。可能智慧合約是與token打交道,而不是輸出字串吧。

四、函式修飾符

function modifier可以讓函式顯得更加簡潔,比如經常判斷一個函式的msg.sender是不是合約構建者時,不需要頻繁插入require(msg.sender == owner);這樣的語句,只需要定義一個modifier。

modifier onlyOwner {
    require(msg.sender == owner);
    _;
}

而在函式宣告的主體尾部加上onlyOwner就可以了。上面的語法中最有意思的是_;這行語句,表示原來函式中的所有語句。當函式中含有return()語句時,替代規則有點特殊。

function test() onlyOwner { 
   // ...
}

payable實際是一個內建的修飾符,表示一個函式在呼叫時要傳送ether。

五、繼承

solidity支援多重繼承,繼承線採用與Python相似的C3 Linearization規則。

contract parent {
    // ...
}
contract child is parent {
    // ...
}

抽象合約是函式只有宣告,沒有具體的實現。

interface與java語言的語法類似,不用多說。

六、多引數返回

在函式的返回值中可以一次返回多個引數,比如:在返回一個數組中的元素的同時,返回它在陣列中所在的位置時,這樣可以一次給多個變數賦值。

function test() returns (address item, uint index) {
    address []arr;
    // ...
    return (arr[1], 1);
}
address owner;
uint i;
(owner, i) = test();
(owner, ) = test(); //如果不需要第2個引數

七、異常處理

在比較早的solidity版本中都用throw(),現在統統用revert(),可以保證在遇到異常時,回滾到呼叫前的狀態。用require可以寫得更簡練。

require(msg.sender == owner);

另外的一個容易讓人搞糊塗的語句是assert,在C語言中,assert翻譯為“斷言”,這類語句只在除錯時起作用,用來排查軟體的重大BUG,這裡也是類似。表示程式在執行到這條語句時,肯定會滿足其中的情況。如果有異常發生,說明軟體肯定有重大的BUG,由於solidity中涉及到轉帳等重要操作,assert失敗後,會耗光所有的GAS,讓交易失敗,防止更嚴重的事情發生。assert常用於陣列越界、元素非空的檢查上。

而require要檢查的是軟體可能經常發生的情況,比如給函式中傳遞的引數時是否滿足一定的條件等等。

八、幾個全域性變數

solidity中內建了msg,block和tx這幾個全域性變數。

  • msg.value,訊息所附帶的貨幣量,單位為wei
  • msg.sig,呼叫資料的前四個位元組,函式識別符號
  • msg.sender,當前呼叫發起人的地址
  • msg.gas,當前剩餘的gas
  • block.difficulty,當前區塊的難度值
  • block.blockhash(),某個區塊的雜湊值
  • block.coinbase,當前區塊礦工的地址
  • block.gaslimit,當前區塊的gas上限
  • block.number,當前區塊的序號
  • block.timestamp,當前區塊的時間戳,是uint型別
  • now,等同於block.timestamp
  • tx.gasprice,交易的gas價格
  • tx.origin,交易的發起人,完整的呼叫鏈

九、可見性

函式的可見性有external、public、internal和private。

狀態變數的可見性有public、internal和private,類似於C++語言中的public、protected和private。

external只能修飾函式,說明這個函式只能被外部合約呼叫。假設函式f()是external,還想在合約內呼叫,可以用this.f()。

十、delete

delete操作可以用於任何變數,將其設定為預設值0。

對可變陣列使用delete,會刪除所有元素,其長度變為0。

對定長陣列使用delete,則會重置所有元素為0,也可以重置指定位置的元素。

對map型別使用delete,什麼也不會發生。

對map型別的一個鍵使用delete,則會刪除與該鍵相關的值。

我學習合約程式設計的目的是什麼呢?

1、手工用imtoken錢包給許多人發代幣是一件非常費力且容易出錯的事,想寫一個合約來自動完成這件事。

2、深入瞭解以太坊的背後原理。

3、智慧合約在寫作社群激勵等很多地方有廣闊的應用前景,程式設計師學會它肯定是站在區塊鏈的頂端,既有趣又賺錢。