Layout of a Solidity Source File
本文檔翻譯自 Solidity docs扁瓢。
源文件可以包含任意數(shù)量的 contract定義蜓堕,import 指令和 pragma 指令丙躏。
Pragmas
pragma
關(guān)鍵字可用于啟用某些編譯器功能或檢查谚攒。 pragma指令始終是源文件的本地指令鸡典,因此如果要在所有項(xiàng)目中啟用它,則必須將pragma添加到所有文件中榛丢。如果 import 另一個文件铲球,該文件中的pragma將不會自動應(yīng)用于導(dǎo)入文件。
Version Pragma
源文件可以(并且應(yīng)該)使用所謂的版本編譯指示進(jìn)行注釋晰赞,以拒絕使用可能引入不兼容更改的未來編譯器版本進(jìn)行編譯稼病。我們嘗試將這些更改保持在絕對最小值,尤其是以語義變化也需要更改語法的方式引入更改掖鱼,但這當(dāng)然不總是可行的然走。因此,至少對于包含重大更改的版本來讀取更改日志總是一個好主意戏挡,這些版本將始終具有 0.x.0
或 x.0.0
形式的版本芍瑞。
版本編譯指示使用如下:
pragma solidity ^0.4.0;
這樣的源文件不會使用早于版本0.4.0的編譯器進(jìn)行編譯,并且它也不能在從版本0.5.0開始的編譯器上工作(通過使用 ^
添加第二個條件)褐墅。這背后的想法是在版本 0.5.0
之前不會有任何重大更改拆檬,因此我們始終可以確保我們的代碼將按照我們的預(yù)期方式進(jìn)行編譯。我們沒有修復(fù)編譯器的確切版本妥凳,因此仍然可以使用bugfix版本竟贯。
可以為編譯器版本指定更復(fù)雜的規(guī)則,表達(dá)式遵循 npm 使用的表達(dá)式猾封。
Note
使用版本編譯指示不會更改編譯器的版本澄耍。它也不會啟用或禁用編譯器的功能。它只是指示編譯器檢查其版本是否與pragma所需的版本匹配晌缘。如果不匹配齐莲,編譯器將發(fā)出錯誤。
Experimental Pragma
第二個pragma是實(shí)驗(yàn)性的pragma磷箕。它可用于啟用默認(rèn)情況下尚未啟用的編譯器或語言的功能选酗。目前支持以下實(shí)驗(yàn)編譯指示:
ABIEncoderV2
新的ABI編碼器能夠?qū)θ我馇短椎臄?shù)組和結(jié)構(gòu)進(jìn)行編碼和解碼。它產(chǎn)生的優(yōu)化代碼不太理想(這部分代碼的優(yōu)化器仍在開發(fā)中)并且沒有像舊編碼器那樣接收到太多的測試岳枷。您可以使用 pragma experimental ABIEncoderV2;
激活它芒填。
SMTChecker
構(gòu)建Solidity編譯器時必須啟用此組件,因此它不適用于所有Solidity二進(jìn)制文件空繁。構(gòu)建說明解釋了如何激活此選項(xiàng)殿衰。它在大多數(shù)版本中為Ubuntu PPA版本激活,但不適用于solc-js盛泡,Docker鏡像闷祥,Windows二進(jìn)制文件或靜態(tài)構(gòu)建的Linux二進(jìn)制文件。
如果您使用 pragma experimental SMTChecker;
傲诵,那么您將獲得通過查詢SMT求解器獲得的其他安全警告凯砍。該組件尚不支持Solidity語言的所有功能箱硕,可能會輸出許多警告。如果報告不支持的功能悟衩,分析可能不完整剧罩。
Importing other Source Files
Syntax and Semantics
Solidity支持與JavaScript中可用的導(dǎo)入語句非常相似的語句(來自ES6),盡管Solidity不知道“默認(rèn)導(dǎo)出”的概念座泳。
在全局級別惠昔,您可以使用以下形式的import語句:
import "filename";
此語句將所有全局符號從“filename”(以及在那里導(dǎo)入的符號)導(dǎo)入當(dāng)前全局范圍(與ES6不同,但向后兼容Solidity)钳榨。建議不要使用這種簡單的形式舰罚,因?yàn)樗鼤圆豢深A(yù)測的方式污染命名空間:如果在“filename”中添加新的頂級項(xiàng),它們將自動出現(xiàn)在所有從“filename”導(dǎo)入的文件中薛耻。最好明確導(dǎo)入特定符號营罢。
以下示例創(chuàng)建一個新的全局符號 symbolName
,其成員是 “filename”
中的所有全局符號饼齿。
import * as symbolName from "filename";
如果存在命名沖突饲漾,您還可以在導(dǎo)入時重命名符號。此代碼創(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
始終被視為帶 /
作為目錄分隔符的路徑泉褐。.
作為當(dāng)前和 ..
作為父目錄。什么時候 .
或 ..
后跟一個字符鸟蜡,除了 /
膜赃,它不被視為當(dāng)前或父目錄。所有路徑名都被視為絕對路徑揉忘,除非它們以當(dāng)前路徑 .
開頭跳座,或者父目錄 ..
。
要從與當(dāng)前文件相同的目錄導(dǎo)入文件 x
泣矛,請使用 import "./x" as x;
疲眷。如果使用 import "x" as x;
相反,可能引用不同的文件(在全局 “include director” 中)您朽。
這取決于編譯器(見下文)如何實(shí)際解析路徑咪橙。通常,目錄層次結(jié)構(gòu)不需要嚴(yán)格映射到本地文件系統(tǒng),它也可以映射到通過發(fā)現(xiàn)的資源美侦,例如 ipfs,http或git魂奥。
Note
始終使用 `import "./filename.sol";` 之類的相對導(dǎo)入菠剩;并避免在路徑說明符中使用 `..`。在后一種情況下耻煤,最好使用全局路徑并設(shè)置重映射具壮,如下所述。
Use in Actual Compilers
調(diào)用編譯器時哈蝇,您可以指定如何發(fā)現(xiàn)路徑的第一個元素以及路徑前綴重映射棺妓。例如,您可以設(shè)置重映射炮赦,以便從您的本地目錄 /usr/local/dapp-bin/library
中實(shí)際讀取從虛擬目錄 github.com/ethereum/dapp-bin/library
導(dǎo)入的所有內(nèi)容怜跑。如果應(yīng)用多個重映射,則首先嘗試具有最長密鑰的那個吠勘。不允許使用空前綴性芬。重映射可以取決于上下文,允許您配置要導(dǎo)入的包剧防,例如植锉,同名庫的不同版本。
solc:
對于solc(命令行編譯器)峭拘,您將這些路徑重映射提供為 context:prefix=target
arguments俊庇,其中 context:
和 = target
部分都是可選的(在這種情況下,target
默認(rèn)為 prefix
)鸡挠。編譯常規(guī)文件的所有重映射值(包括它們的依賴關(guān)系)辉饱。
這種機(jī)制是向后兼容的(只要沒有文件名包含 =
或 :
),因此不會發(fā)生重大變化宵凌。導(dǎo)入以 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;
然后運(yùn)行編譯器:
solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol
作為一個更復(fù)雜的示例溜腐,假設(shè)您依賴于使用您簽出到 /usr/local/dapp-bin_old
的舊版dapp-bin的模塊,那么您可以運(yùn)行:
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
中的所有導(dǎo)入都指向舊版本瓜喇,但 module1
中的導(dǎo)入指向新版本挺益。
Note
`solc` 只允許您包含某些目錄中的文件。它們必須位于其中一個顯式指定的源文件的目錄(或子目錄)中乘寒,或者位于重映射目標(biāo)的目錄(或子目錄)中望众。如果要允許直接絕對包含,請?zhí)砑又赜成?`/=/`。
如果存在多個導(dǎo)致有效文件的重映射烂翰,則選擇具有最長公共前綴的重映射夯缺。
Remix:
Remix 為GitHub提供自動重映射,并通過網(wǎng)絡(luò)自動檢索文件甘耿。您可以導(dǎo)入上面的可迭代映射踊兜,例如
::
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)終止倾剿。注釋后終結(jié)符仍然是源代碼的一部分筷频,因此如果它不是ascii符號(這些是NEL,LS和PS)柱告,則會導(dǎo)致解析器錯誤截驮。
此外,還有另一種稱為natspec注釋的注釋际度,其文檔尚未編寫葵袭。它們使用三斜杠 (///) 或雙星號塊 (/** ... */) 編寫,它們應(yīng)直接在函數(shù)聲明或語句之上使用乖菱。您可以在這些注釋中使用 Doxygen樣式 的標(biāo)記來記錄函數(shù)坡锡,注釋形式驗(yàn)證的條件,并提供在用戶嘗試調(diào)用函數(shù)時向用戶顯示的確認(rèn)文本窒所。
在下面的示例中鹉勒,我們記錄了合約的標(biāo)題,兩個函數(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);
}
}
項(xiàng)目源代碼
項(xiàng)目源代碼會逐步上傳到 Github禽额,地址為 https://github.com/windstamp/dapp。
Contributor
- Windstamp, https://github.com/windstamp