寫在前面:HiBlock區塊鏈社區成立了翻譯小組,翻譯區塊鏈相關的技術文檔及資料,本文爲Solidity文檔翻譯的第四部分《深刻理解Solidity之源文件及合約結構》,特發佈出來邀請solidity愛好者、開發者作公開的審校,您能夠添加微信baobaotalk_com,驗證輸入「solidity」,而後將您的意見和建議發送給咱們,也能夠在文末「留言」區留言,有效的建議咱們會採納及合併進下一版本,同時將送一份小禮物給您以示感謝。git
Solidity 源文件結構github
源文件中能夠包含任意多個合約定義、導入指令和雜注指令。npm
爲了不將來被可能引入不兼容變動的編譯器所編譯,源文件能夠(也應該)被所謂的版本 雜注pragma所註解。 咱們力圖把這類變動作到儘量小,特別是,咱們須要以一種當修改語義時必須同步修改語法的方式引入變動,固然這有時候也難以作到。 所以,至少對含重大變動的版本,通讀變動日誌永遠是好辦法。 這些版本的版本號始終是 0.x.0 或者 x.0.0 的形式。編程
版本雜注使用以下:微信
pragma solidity ^0.4.0;網絡
這樣,源文件將既不容許低於 0.4.0 版本的編譯器編譯, 也不容許高於(包含) 0.5.0 版本的編譯器編譯(第二個條件因使用 ^ 被添加)。 這種作法的考慮是,編譯器在 0.5.0 版本以前不會有重大變動,因此可確保源代碼始終按預期被編譯。 上面例子中不固定編譯器的具體版本號,所以編譯器的補丁版也可使用。app
可使用更復雜的規則來指定編譯器的版本,表達式遵循 npm 版本語義。編程語言
語法與語義函數
雖然 Solidity 不知道 "default export" 爲什麼物, 可是 Solidity 所支持的導入語句,其語法同 JavaScript(從 ES6 起)很是相似。工具
在全局層面上,可以使用以下格式的導入語句:
import "filename";
此語句將從 「filename」 中導入全部的全局符號到當前全局做用域中(不一樣於 ES6,Solidity 是向後兼容的)。
import * as symbolName from "filename";
...建立一個新的全局符號 symbolName,其成員均來自 "filename" 中全局符號。
import {symbol1 as alias, symbol2} from "filename";
...建立新的全局符號 alias 和 symbol2,分別從 "filename" 引用 symbol1 和 symbol2 。
另外一種語法不屬於 ES6,但或許更簡便:
import "filename" as symbolName;
這條語句等同於
import * as symbolName from "filename";
路徑
上文中的 filename 老是會按路徑來處理,以 / 做爲目錄分割符、以 . 標示當前目錄、以 .. 表示父目錄。 當 . 或 .. 後面跟隨的字符是 / 時,它們才能被當作當前目錄或父目錄。 只有路徑以當前目錄 . 或父目錄 .. 開頭時,才能被視爲相對路徑。
用 import "./x" as x; 語句導入當前源文件同目錄下的文件 x 。 若是用 import "x" as x; 代替,可能會引入不一樣的文件(在全局 include directory 中)。
最終導入哪一個文件取決於編譯器(見下文)究竟是怎樣解析路徑的。 一般,目錄層次沒必要嚴格映射到本地文件系統, 它也能夠映射到能經過諸如 ipfs,http 或者 git 發現的資源。
在實際的編譯器中使用
當運行編譯器時,它不只能指定如何發現路徑的第一個元素,還可指定路徑前綴 重映射remapping。 例如,github.com/ethereum/dapp-bin/library 會被重映射到 /usr/local/dapp-bin/library , 此時編譯器將從重映射位置讀取文件。若是重映射到多個路徑,優先嚐試重映射路徑最長的一個。 這容許將好比 "" 被映射到 "/usr/local/include/solidity" 來進行「回退重映射」。 同時,這些重映射可取決於上下文,容許你配置要導入的包,好比同一個庫的不一樣版本。
solc:
對於 solc(命令行編譯器),這些重映射以 context:prefix=target 形式的參數提供。 其中,context: 和 =target 部分是可選的(此時 target 默認爲 prefix )。 全部重映射的值都是被編譯過的常規文件(包括他們的依賴),這個機制徹底是向後兼容的(只要文件名不包含 = 或 : ), 所以這不是一個破壞性修改。 在 content 目錄或其子目錄中的源碼文件中,全部導入語句裏以 prefix 開頭的導入文件都將被用 target 替換 prefix 來重定向。
舉個例子,若是你已克隆 github.com/ethereum/dapp-bin/ 到本地 /usr/local/dapp-bin , 可在源文件中使用:
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
而後運行編譯器:
solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol
舉個更復雜的例子,假設你依賴了一些使用了很是舊版本的 dapp-bin 的模塊。 舊版本的 dapp-bin 已經被 checkout 到 /usr/local/dapp-bin_old ,此時你可以使用:
solc module1:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ \
module2:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin_old/ source.sol
這樣, module2 中的全部導入都指向舊版本,而 module1 中的導入則獲取新版本。
注意, solc 只容許包含來自特定目錄的文件:它們必須位於顯式地指定的源文件目錄(或子目錄)中,或者重映射的目標目錄(或子目錄)中。 若是你想直接用絕對路徑來包含文件,只需添加劇映射 =/。
若是有多個重映射指向一個有效文件,那麼具備最長公共前綴的重映射會被選用。
Remix:
Remix 提供一個爲 github 源代碼平臺的自動重映射,它將經過網絡自動獲取文件: 好比,你可使用
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
導入一個 map 迭代器。
將來, Remix 可能支持其餘源代碼平臺。
可使用單行註釋(//)和多行註釋(/.../)
// 這是一個單行註釋。
/*
這是一個多行註釋。
*/
此外,有另外一種註釋稱爲 natspec 註釋,其文檔還還沒有編寫。 它們是用三個反斜槓(///)或雙星號開頭的塊(/** ... */)書寫,它們應該直接在函數聲明或語句上使用。 可在註釋中使用 Doxygen 樣式的標籤來文檔化函數、 標註形式校驗經過的條件,和提供一個當用戶試圖調用一個函數時顯示給用戶的 確認文本。
在下面的例子中,咱們記錄了合約的標題、兩個入參和兩個返回值的說明:
pragma solidity ^0.4.0;
/* @title 形狀計算器。 /
*contract shapeCalculator { * / @dev 求矩形代表面積與周長。
* * @param w 矩形寬度。 *
* * @param h 矩形高度。 *
* * @return s 求得表面積。 *
* * @return p 求得周長。 *
* / function rectangle(uint w, uint h) returns (uint s, uint p) { s = w ***** h; p** =** 2 ***** (w + h); }
}
在 Solidity 中,合約相似於面向對象編程語言中的類。 每一個合約中能夠包含 狀態變量、 函數、 函數修飾器、事件、 結構類型、 和 枚舉類型 的聲明,且合約能夠從其餘合約繼承。
狀態變量是永久地存儲在合約存儲中的值。
pragma solidity ^0.4.0;
contract SimpleStorage { ** uint** storedData; // 狀態變量 // ...
}
有效的狀態變量類型參閱 類型 章節, 對狀態變量可見性有可能的選擇參閱 Visibility and Getters 。
函數是合約中代碼的可執行單元。
pragma solidity ^0.4.0;
contract SimpleAuction { function bid() public payable { // 函數 // ... }
}
Function Calls 可發生在合約內部或外部,且函數對其餘合約有不一樣程度的可見性( Visibility and Getters)。
函數修飾器能夠用來以聲明的方式改良函數語義(參閱合約章節中 Function Modifiers)。
pragma solidity ^0.4.11;
**contract **Purchase { address public seller;
**modifier **onlySeller() { // 修飾器 require(msg.sender == seller); _; }
** function** abort() **public **onlySeller { // Modifier usage // ... }
}
事件是與以太坊虛擬機日誌工具的方便接口。
pragma solidity ^0.4.0;
**contract **SimpleAuction {
event HighestBidIncreased(address bidder, uint amount);* // 事件*
** function** bid() public payable { // ... HighestBidIncreased(msg.sender, msg.value); // 觸發事件 }
}
有關如何聲明事件和如何在 dapp 中使用事件的信息,參閱合約章節中的 Events。
結構是能夠將幾個變量分組的自定義類型(參閱類型章節中的 Structs)。
pragma solidity ^0.4.0;
**contract **Ballot { ** struct Voter { // 結構 uint weight; bool voted; address delegate; uint vote; }
}
枚舉可用來建立有必定數量的值的自定義類型(參閱類型章節中的 Enums)。
pragma solidity ^0.4.0;
contract Purchase { enum State { Created, Locked, Inactive } // 枚舉
}
本文內容來源於HiBlock區塊鏈社區翻譯小組,感謝全體譯者的辛苦工做。
注:本文爲solidity翻譯的第四部分《深刻理解Solidity之源文件及合約結構》,特發佈出來邀請solidity愛好者、開發者作公開的審校,您能夠添加微信baobaotalk_com,驗證輸入「solidity」,而後將您的意見和建議發送給咱們,也可在文末「留言」區留言,或經過原文連接訪問咱們的Github。有效的建議咱們會收納並及時改進,同時將送一份小禮物給您以示感謝。
課程回放:(識別圖中二維碼便可觀看視頻)
如下是咱們的社區介紹,歡迎各類合做、交流、學習:)