Layout of a Solidity Source File
本文檔翻譯自 Solidity docs。
源文件可以包含任意數(shù)量的 contract定義,import 指令和 pragma 指令。
Pragmas
pragma 關鍵字可用于啟用某些編譯器功能或檢查。 pragma指令始終是源文件的本地指令,因此如果要在所有項目中啟用它,則必須將pragma添加到所有文件中。如果 import 另一個文件,該文件中的pragma將不會自動應用于導入文件。
Version Pragma
源文件可以(并且應該)使用所謂的版本編譯指示進行注釋,以拒絕使用可能引入不兼容更改的未來編譯器版本進行編譯。我們嘗試將這些更改保持在絕對最小值,尤其是以語義變化也需要更改語法的方式引入更改,但這當然不總是可行的。因此,至少對于包含重大更改的版本來讀取更改日志總是一個好主意,這些版本將始終具有 0.x.0 或 x.0.0 形式的版本。
版本編譯指示使用如下:
pragma solidity ^0.4.0;
這樣的源文件不會使用早于版本0.4.0的編譯器進行編譯,并且它也不能在從版本0.5.0開始的編譯器上工作(通過使用 ^ 添加第二個條件)。這背后的想法是在版本 0.5.0 之前不會有任何重大更改,因此我們始終可以確保我們的代碼將按照我們的預期方式進行編譯。我們沒有修復編譯器的確切版本,因此仍然可以使用bugfix版本。
可以為編譯器版本指定更復雜的規(guī)則,表達式遵循 npm 使用的表達式。
Note
使用版本編譯指示不會更改編譯器的版本。它也不會啟用或禁用編譯器的功能。它只是指示編譯器檢查其版本是否與pragma所需的版本匹配。如果不匹配,編譯器將發(fā)出錯誤。
Experimental Pragma
第二個pragma是實驗性的pragma。它可用于啟用默認情況下尚未啟用的編譯器或語言的功能。目前支持以下實驗編譯指示:
ABIEncoderV2
新的ABI編碼器能夠?qū)θ我馇短椎臄?shù)組和結構進行編碼和解碼。它產(chǎn)生的優(yōu)化代碼不太理想(這部分代碼的優(yōu)化器仍在開發(fā)中)并且沒有像舊編碼器那樣接收到太多的測試。您可以使用 pragma experimental ABIEncoderV2; 激活它。
SMTChecker
構建Solidity編譯器時必須啟用此組件,因此它不適用于所有Solidity二進制文件。構建說明解釋了如何激活此選項。它在大多數(shù)版本中為Ubuntu PPA版本激活,但不適用于solc-js,Docker鏡像,Windows二進制文件或靜態(tài)構建的Linux二進制文件。
如果您使用 pragma experimental SMTChecker;,那么您將獲得通過查詢SMT求解器獲得的其他安全警告。該組件尚不支持Solidity語言的所有功能,可能會輸出許多警告。如果報告不支持的功能,分析可能不完整。
Importing other Source Files
Syntax and Semantics
Solidity支持與JavaScript中可用的導入語句非常相似的語句(來自ES6),盡管Solidity不知道“默認導出”的概念。
在全局級別,您可以使用以下形式的import語句:
import "filename";
此語句將所有全局符號從“filename”(以及在那里導入的符號)導入當前全局范圍(與ES6不同,但向后兼容Solidity)。建議不要使用這種簡單的形式,因為它會以不可預測的方式污染命名空間:如果在“filename”中添加新的頂級項,它們將自動出現(xiàn)在所有從“filename”導入的文件中。最好明確導入特定符號。
以下示例創(chuàng)建一個新的全局符號 symbolName,其成員是 “filename” 中的所有全局符號。
import * as symbolName from "filename";
如果存在命名沖突,您還可以在導入時重命名符號。此代碼創(chuàng)建新的全局符號 alias 和 symbol2,它們分別從 “filename” 中引用 symbol1 和 symbol2。
import {symbol1 as alias, symbol2} from "filename";
另一種語法不是ES6的一部分,但可能很方便:
import "filename" as symbolName;
等價于 import * as symbolName from "filename";。
Note
如果使用 import “filename.sol” 作為 moduleName;,則從 “filename.sol” 中作為 moduleName.C 訪問名為 C 的合約,而不是直接使用 C.
Paths
在上面,filename 始終被視為帶 / 作為目錄分隔符的路徑。. 作為當前和 .. 作為父目錄。什么時候 . 或 .. 后跟一個字符,除了 /,它不被視為當前或父目錄。所有路徑名都被視為絕對路徑,除非它們以當前路徑 . 開頭,或者父目錄 ..。
要從與當前文件相同的目錄導入文件 x,請使用 import "./x" as x;。如果使用 import "x" as x; 相反,可能引用不同的文件(在全局 “include director” 中)。
這取決于編譯器(見下文)如何實際解析路徑。通常,目錄層次結構不需要嚴格映射到本地文件系統(tǒng),它也可以映射到通過發(fā)現(xiàn)的資源,例如 ipfs,http或git。
Note
始終使用 `import "./filename.sol";` 之類的相對導入;并避免在路徑說明符中使用 `..`。在后一種情況下,最好使用全局路徑并設置重映射,如下所述。
Use in Actual Compilers
調(diào)用編譯器時,您可以指定如何發(fā)現(xiàn)路徑的第一個元素以及路徑前綴重映射。例如,您可以設置重映射,以便從您的本地目錄 /usr/local/dapp-bin/library 中實際讀取從虛擬目錄 github.com/ethereum/dapp-bin/library 導入的所有內(nèi)容。如果應用多個重映射,則首先嘗試具有最長密鑰的那個。不允許使用空前綴。重映射可以取決于上下文,允許您配置要導入的包,例如,同名庫的不同版本。
solc:
對于solc(命令行編譯器),您將這些路徑重映射提供為 context:prefix=target arguments,其中 context: 和 = target 部分都是可選的(在這種情況下,target 默認為 prefix)。編譯常規(guī)文件的所有重映射值(包括它們的依賴關系)。
這種機制是向后兼容的(只要沒有文件名包含 = 或 :),因此不會發(fā)生重大變化。導入以 prefix 開頭的文件的 context 目錄中或下面的所有文件都通過將 prefix 替換為 target 來重定向。
例如,如果將 github.com/ethereum/dapp-bin/ 本地克隆到 /usr/local/dapp-bin,則可以在源文件中使用以下內(nèi)容:
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
作為一個更復雜的示例,假設您依賴于使用您簽出到 /usr/local/dapp-bin_old 的舊版dapp-bin的模塊,那么您可以運行:
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 中的導入指向新版本。
Note
`solc` 只允許您包含某些目錄中的文件。它們必須位于其中一個顯式指定的源文件的目錄(或子目錄)中,或者位于重映射目標的目錄(或子目錄)中。如果要允許直接絕對包含,請?zhí)砑又赜成?`/=/`。
如果存在多個導致有效文件的重映射,則選擇具有最長公共前綴的重映射。
Remix:
Remix 為GitHub提供自動重映射,并通過網(wǎng)絡自動檢索文件。您可以導入上面的可迭代映射,例如
::
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
Remix可能會在將來添加其他源代碼提供程序。
Comments
可以使用單行注釋 (//) 和多行注釋 (/.../)。
// This is a single-line comment.
/*
This is a
multi-line comment.
*/
Note
單行注釋由utf8編碼中的任何unicode行終止符(LF,VF,F(xiàn)F,CR,NEL,LS或PS)終止。注釋后終結符仍然是源代碼的一部分,因此如果它不是ascii符號(這些是NEL,LS和PS),則會導致解析器錯誤。
此外,還有另一種稱為natspec注釋的注釋,其文檔尚未編寫。它們使用三斜杠 (///) 或雙星號塊 (/** ... */) 編寫,它們應直接在函數(shù)聲明或語句之上使用。您可以在這些注釋中使用 Doxygen樣式 的標記來記錄函數(shù),注釋形式驗證的條件,并提供在用戶嘗試調(diào)用函數(shù)時向用戶顯示的確認文本。
在下面的示例中,我們記錄了合約的標題,兩個函數(shù)參數(shù)的說明和兩個返回變量。
pragma solidity >=0.4.0 <0.6.0;
/** @title Shape calculator. */
contract ShapeCalculator {
/** @dev Calculates a rectangle's surface and perimeter.
* @param w Width of the rectangle.
* @param h Height of the rectangle.
* @return s The calculated surface.
* @return p The calculated perimeter.
*/
function rectangle(uint w, uint h) public pure returns (uint s, uint p) {
s = w * h;
p = 2 * (w + h);
}
}
項目源代碼
項目源代碼會逐步上傳到 Github,地址為 https://github.com/windstamp/dapp。
Contributor
- Windstamp, https://github.com/windstamp