本指南用于提供編寫Solidity的編碼規(guī)范,本指南會隨著后續(xù)需求不斷修改演進,可能會增加新的更合適的規(guī)范,舊的不適合的規(guī)范會被廢棄。
當然,很多項目可能有自己的編碼規(guī)范,如果存在沖突,請參考項目的編碼規(guī)范。
本指南的結(jié)構(gòu)及規(guī)范建議大都來自于python的pep8編碼規(guī)范。
本指南不是說必須完全按照指南的要求進行solidity編碼,而是提供一個總體的一致性要求,這個和pep8的理念相似(譯注:pep8的理念大概是:強制的一致性是非常愚蠢的行為,參見:pep8)。
本指南是為了提供編碼風(fēng)格的一致性,因此一致性這一理念是很重要的,在項目中編碼風(fēng)格的一致性更加重要,而在同一個函數(shù)或模塊中風(fēng)格的一致性是最重要的。而最最最重要的是:你要知道什么時候需要保持一致性,什么時候不需要保持一致性,因為有時候本指南不一定適用,你需要根據(jù)自己的需要進行權(quán)衡??梢詤⒖枷逻叺睦記Q定哪一種對你來說是最合適的。
縮進
每行使用4個空格縮進
tab或空格
空格是首選縮進方式
禁止tab和空格混合使用
回車(空行)
兩個合約之間增加兩行空行
規(guī)范的方式:
contract?A {
??? ...}
contract?B {
??? ...}
contract?C {
??? ...}
不規(guī)范的方式:
contract?A {
??? ...}contract?B {
??? ...}
contract?C {
??? ...}
合約內(nèi)部函數(shù)之間需要回車,如果是函數(shù)聲明和函數(shù)實現(xiàn)一起則需要兩個回車
規(guī)范的方式:
contract?A {
????function?spam();
????function?ham();
}
contract?B is A {
????function?spam() {
??????? ...
??? }
????function?ham() {
??????? ...
??? }
}
不規(guī)范的方式:
contract?A {
????function?spam() {
??????? ...
??? }
????function?ham() {
??????? ...
??? }}
首選UTF-8或者ASCII編碼
一般在代碼開始進行引入聲明
規(guī)范的方式:
import?"owned";
contract?A {
??? ...}
contract?B is owned {
??? ...}
不規(guī)范的方式:
contract?A {
??? ...}
import?"owned";
contract?B is owned {
??? ...}
表達式中的空格使用方法
以下場景避免使用空格
Yes規(guī)范的方式: spam(ham[1], Coin({name: “ham”}));
No不規(guī)范的方式: spam( ham[ 1 ], Coin( { name: “ham” } ) );
Yes規(guī)范的方式: function spam(uint i, Coin coin);
No不規(guī)范的方式: function spam(uint i , Coin coin) ;
規(guī)范的方式:
x?=?1;
y?=?2;
long_variable?=?3;
不規(guī)范的方式:
x?????????????=?1;
y?????????????=?2;
long_variable?=?3;
控制結(jié)構(gòu)
合約、庫。函數(shù)、結(jié)構(gòu)體的花括號使用方法:
左花括號和聲明同一行
右括號和左括號聲明保持相同縮進位置。
規(guī)范的方式:
contract?Coin {
????struct?Bank {
????????address?owner;
????????uint?balance;
??? }
}
不規(guī)范的方式:
contract?Coin
{
????struct?Bank {
????????address?owner;
????????uint?balance;
??? }
}
以上建議也同樣適用于if、else、while、for。
此外,if、while、for條件語句之間必須空行
規(guī)范的方式:
if?(...) {
??? ...
}
for?(...) {
??? ...
}
不規(guī)范的方式:
if?(...)
{
??? ...
}
while(...)
{
}
for?(...)
?{
??? ...;
}
對于控制結(jié)構(gòu)內(nèi)部如果只有單條語句可以不需要使用括號。
規(guī)范的方式:
if?(x?<?10)
??? x?+=?1;
不規(guī)范的方式:
if?(x?<?10)
??? someArray.push(Coin({
??????? name:?'spam',
??????? value:?42
??? }));
對于if語句如果包含else或者else if語句,則else語句要新起一行。else和else if的內(nèi)部規(guī)范和if相同。
規(guī)范的方式:
if?(x?<?3) {
??? x?+=?1;
}
else?{
??? x?-=?1;
}
if?(x?<?3)
??? x?+=?1;
else
??? x?-=?1;
不規(guī)范的方式:
if?(x?<?3) {
??? x?+=?1;}?
else?{
??? x?-=?1;}
對于簡短函數(shù)聲明,建議將函數(shù)體的左括號和函數(shù)名放在同一行。
右括號和函數(shù)聲明保持相同的縮進。
左括號和函數(shù)名之間要增加一個空格。
function?increment(uint?x)?returns?(uint) {
????return?x?+?1;
}
function?increment(uint?x)?public?onlyowner?returns?(uint) {
????return?x?+?1;
}
不規(guī)范的方式:
function?increment(uint?x)?returns?(uint)
{
????return?x?+?1;
}
function?increment(uint?x)?returns?(uint)
{
????return?x?+?1;
}
function?increment(uint?x)?returns?(uint)
?{
????return?x?+?1;
}
function?increment(uint?x)?returns?(uint)?
{
????return?x?+?1;
}
默認修飾符應(yīng)該放在其他自定義修飾符之前。
規(guī)范的方式:
function?kill()?public?onlyowner {
??? selfdestruct(owner);
}
不規(guī)范的方式:
function?kill() onlyowner?public?{
??? selfdestruct(owner);
}
對于參數(shù)較多的函數(shù)聲明可將所有參數(shù)逐行顯示,并保持相同的縮進。函數(shù)聲明的右括號和函數(shù)體左括號放在同一行,并和函數(shù)聲明保持相同的縮進。
規(guī)范的方式:
function?thisFunctionHasLotsOfArguments(
????address?a,
????address?b,
????address?c,
????address?d,
????address?e,
????address?f,
) {
??? do_something;
}
不規(guī)范的方式:
function?thisFunctionHasLotsOfArguments(address?a,?address?b,?address?c,
????address?d,?address?e,?address?f) {
??? do_something;
}
function?thisFunctionHasLotsOfArguments(address?a,
????????????????????????????????????????address?b,
????????????????????????????????????????address?c,
????????????????????????????????????????address?d,
????????????????????????????????????????address?e,
????????????????????????????????????????address?f) {
??? do_something;
}
function?thisFunctionHasLotsOfArguments(
????address?a,
????address?b,
????address?c,
????address?d,
????address?e,
????address?f) {
??? do_something;
}
如果函數(shù)包括多個修飾符,則需要將修飾符分行并逐行縮進顯示。函數(shù)體左括號也要分行。
規(guī)范的方式:
function?thisFunctionNameIsReallyLong(address?x,?address?y,?address?z)
????public
??? onlyowner
??? priced
????returns?(address)
{
??? do_something;
}
function?thisFunctionNameIsReallyLong(
????address?x,
????address?y,
????address?z,)
????public
??? onlyowner
??? priced
????returns?(address)
{
??? do_something;
}
不規(guī)范的方式:
function?thisFunctionNameIsReallyLong(address?x,?address?y,?address?z)
??????????????????????????????????????public
????????????????????????????????????? onlyowner
????????????????????????????????????? priced
??????????????????????????????????????returns?(address) {
??? do_something;
}
function?thisFunctionNameIsReallyLong(address?x,?address?y,?address?z)
????public?onlyowner priced?returns?(address){
??? do_something;
}
function?thisFunctionNameIsReallyLong(address?x,?address?y,?address?z)
????public
??? onlyowner
??? priced
????returns?(address) {
??? do_something;
}
對于需要參數(shù)作為構(gòu)造函數(shù)的派生合約,如果函數(shù)聲明太長或者難于閱讀,建議將其構(gòu)造函數(shù)中涉及基類的構(gòu)造函數(shù)分行獨立顯示。
規(guī)范的方式:
contract?A is B, C, D {
????function?A(uint?param1,?uint?param2,?uint?param3,?uint?param4,?uint?param5)
??????? B(param1)
??????? C(param2, param3)
??????? D(param4)
??? {
????????// do something with param5
??? }
}
不規(guī)范的方式:
contract?A is B, C, D {
????function?A(uint?param1,?uint?param2,?uint?param3,?uint?param4,?uint?param5)
??? B(param1)
??? C(param2, param3)
??? D(param4)
??? {
????????// do something with param5
??? }
}
contract?A is B, C, D {
????function?A(uint?param1,?uint?param2,?uint?param3,?uint?param4,?uint?param5)
??????? B(param1)
??????? C(param2, param3)
??????? D(param4) {
????????// do something with param5
??? }
}
對于函數(shù)聲明的編程規(guī)范主要用于提升可讀性,本指南不可能囊括所有編程規(guī)范,對于不涉及的地方,程序猿可發(fā)揮自己的主觀能動性。
映射 待完成
變量聲明
對于數(shù)組變量聲明,類型和數(shù)組中括號直接不能有空格。
規(guī)范的方式: uint[] x; 不規(guī)范的方式: uint [] x;
其他建議
規(guī)范的方式:
x?=?3;x?=?100?/?10;x?+=?3?+?4;x?|=?y?&&?z;
不規(guī)范的方式:
x=3;x?=?100/10;x?+=?3+4;x?|=?y&&z;
規(guī)范的方式:
x = 2**3 + 5;x = 2***y + 3*z;x = (a+b) * (a-**b);
不規(guī)范的方式:
x = 2** 3 + 5;x = y+z;x +=1;
命名規(guī)范
命名規(guī)范是強大且廣泛使用的,使用不同的命名規(guī)范可以傳遞不同的信息。
以下建議是用來提升代碼的可讀性,因此被規(guī)范不是規(guī)則而是用于幫助更好的解釋相關(guān)代碼。
最后,編碼風(fēng)格的一致性是最重要的。
命名方式
為了防止混淆,以下命名用于說明(描述)不同的命名方式。
b(單個小寫字母)
B(單個大寫字母)
小寫
有下劃線的小寫
大寫
有下劃線的大寫
CapWords規(guī)范(首字母大寫)
混合方式(與CapitalizedWords的不同在于首字母小寫!)
注意
當使用CapWords規(guī)范(首字母大寫)的縮略語時,縮略語全部大寫,比如HTTPServerError 比HttpServerError就好理解一點。
避免的命名方式
l?- Lowercase letter el? 小寫的l
O?- Uppercase letter oh?大寫的o
永遠不要用字符‘l'(小寫字母el(就是讀音,下同)),‘O'(大寫字母oh),或‘I'(大寫字母eye)作為單字符的變量名。在某些字體中這些字符不能與數(shù)字1和0分辨。試著在使用‘l'時用‘L'代替。?
合約及庫的命名
合約應(yīng)該使用CapWords規(guī)范命名(首字母大寫)。
事件
事件應(yīng)該使用CapWords規(guī)范命名(首字母大寫)。
函數(shù)命名
函數(shù)名使用大小寫混合
函數(shù)參數(shù)命名
當定義一個在自定義結(jié)構(gòu)體上的庫函數(shù)時,結(jié)構(gòu)體的名稱必須具有自解釋能力。
局部變量命名
大小寫混合
常量命名
常量全部使用大寫字母并用下劃線分隔。
修飾符命名
功能修飾符使用小寫字符并用下劃線分隔。
避免沖突
當和內(nèi)置或者保留名稱沖突時建議使用本規(guī)范。
通用建議
待完成