本文目的是约定 solidity 代码的编码规范,保持代码的 一致性,方便阅读和理解。下面是官方推荐及总结的规范和风格。
另外本人也在找【合约开发】方面的工作,有公司内推的朋友可以和我说说哈
一、源文件编码格式
首选 UTF-8 或 ASCII 编码。
二、代码结构
缩进
- 每个缩进级别使用4个空格。
制表符或空格
-空格是首选的缩进方法。
-应该避免混合使用制表符和空格。
空行
在 solidity 源码中合约声明之间留出两个空行。
正确写法:
contract A {
...
}
contract B {
...
}
contract C {
...
}
错误写法:
contract A {
...
}
contract B {
...
}
contract C {
...
}
在一个合约中的函数声明之间留有一个空行。在相关联的各组单行语句之间可以省略空行。(例如抽象合约的 stub 函数)
正确写法:
contract A {
function spam() public;
function ham() public;
}
contract B is A {
function spam() public {
...
}
function ham() public {
...
}
}
错误写法:
contract A {
function spam() public {
...
}
function ham() public {
...
}
}
代码行的最大长度
将代码行的字符长度控制在 79(或 99)字符容易阅读代码。
折行时应该遵从以下指引:
-
第一个参数不应该紧跟在左括号后边
-
用一个、且只用一个缩进
-
每个函数应该单起一行
-
结束符号 ); 应该单独放在最后一行
函数调用
正确写法:
thisFunctionCallIsReallyLong(
longArgument1,
longArgument2,
longArgument3
);
错误写法:
thisFunctionCallIsReallyLong(longArgument1,
longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(longArgument1,
longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(
longArgument1, longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(
longArgument1,
longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(
longArgument1,
longArgument2,
longArgument3);
赋值语句
正确写法:
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(
argument1,
argument2,
argument3,
argument4
);
错误写法:
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1,
argument2,
argument3,
argument4);
事件定义和事件发生
正确写法:
event LongAndLotsOfArgs(
adress sender,
adress recipient,
uint256 publicKey,
uint256 amount,
bytes32[] options
);
LongAndLotsOfArgs(
sender,
recipient,
publicKey,
amount,
options
);
错误写法:
event LongAndLotsOfArgs(adress sender,
adress recipient,
uint256 publicKey,
uint256 amount,
bytes32[] options);
LongAndLotsOfArgs(sender,
recipient,
publicKey,
amount,
options);
三、Imports 规范
Import 语句应始终放在文件的顶部
import "owned";
contract A {
...
}
contract B is owned {
...
}
四、函数顺序
排序有助于识别他们可以调用哪些函数,并更容易地找到构造函数和 fallback 函数的定义。
函数应根据其可见性和顺序进行分组:
-
构造函数
-
fallback 函数(如果存在)
-
外部函数
-
公共函数
-
内部函数和变量
-
私有函数和变量
在一个分组中,把 view 和 pure 函数放在最后。
正确写法:
contract A {
function A() public {
...
}
function() public {
...
}
// 外部函数
// ...
// 外部的view函数
// ...
// 外部的pure函数
// ...
// 公共函数
// ...
// 内部函数
// ...
// 私有函数
// ...
}
五、表达式中的空格
在以下情况下避免无关的空格:
除单行函数声明外,紧接着小括号,中括号或者大括号的内容应该避免使用空格。
正确写法:
spam(ham[1], Coin({name: "ham"}));
错误写法:
spam( ham[ 1 ], Coin( { name: "ham" } ) );
除外:
function singleLine() public { spam(); }
赋值或其他操作符两边多于一个的空格:
正确写法:
x = 1;
y = 2;
long_variable = 3;
错误写法:
x = 1;
y = 2;
long_variable = 3;
fallback 函数中不要包含空格
正确写法:
function() public {
...
}
错误写法:
function () public {
...
}
六、控制结构
用大括号表示一个合约,库、函数和结构。对于控制结构 if, else, while, for 的实施同样的建议。
-
开括号与声明应在同一行。
-
闭括号在与之前函数声明对应的开括号保持同一缩进级别上另起一行。
-
开括号前应该有一个空格。
正确写法:
contract Coin {
struct Bank {
address owner;
uint balance;
}
}
错误写法:
contract Coin
{
struct Bank {
address owner;
uint balance;
}
}
对于控制结构, 如果 其主体内容只包含一行,则可以省略括号。
正确写法:
if (x < 10)
x += 1;
错误写法:
if (x < 10)
someArray.push(Coin({
name: 'spam',
value: 42
}));
对于具有 else 或 else if 子句的 if 块, else 应该是与 if 的闭大括号放在同一行上。这一规则区别于 其他块状结构。
正确写法:
if (x < 3) {
x += 1;
} else if (x > 7) {
x -= 1;
} else {
x = 5;
}
if (x < 3)
x += 1;
else
x -= 1;
错误写法:
if (x < 3) {
x += 1;
}
else {
x -= 1;
}
七、函数声明
对于简短的函数声明,建议函数体的开括号与函数声明保持在同一行。
闭大括号应该与函数声明的缩进级别相同。
开大括号之前应该有一个空格。
正确写法:
function increment(uint x) public pure returns (uint) {
return x + 1;
}
function increment(uint x) public pure onlyowner returns (uint) {
return x + 1;
}
错误写法:
function increment(uint x) public pure returns (uint)
{
return x + 1;
}
function increment(uint x) public pure returns (uint){
return x + 1;
}
function increment(uint x) public pure returns (uint) {
return x + 1;
}
function increment(uint x) public pure returns (uint) {
return x + 1;}
严格地标示所有函数的可见性,包括构造函数。
正确写法:
function explicitlyPublic(uint val) public {
doSomething();
}
错误写法:
function implicitlyPublic(uint val) {
doSomething();
}
函数的可见性修饰符应该出现在任何自定义修饰符之前。
正确写法:
function kill() public onlyowner {
selfdestruct(owner);
}
错误写法:
function kill() onlyowner public {
selfdestruct(owner);
}
对于长函数声明,建议将每个参数独立一行并与函数体保持相同的缩进级别。闭括号和开括号也应该 独立一行并保持与函数声明相同的缩进级别。
正确写法:
function thisFunctionHasLotsOfArguments(
address a,
address b,
address c,
address d,
address e,
address f
)
public
{
doSomething();
}
错误写法:
function thisFunctionHasLotsOfArguments(address a, address b, address c,
address d, address e, address f) public {
doSomething();
}
function thisFunctionHasLotsOfArguments(address a,
address b,
address c,
address d,
address e,
address f) public {
doSomething();
}
function thisFunctionHasLotsOfArguments(
address a,
address b,
address c,
address d,
address e,
address f) public {
doSomething();
}
如果一个长函数声明有修饰符,那么每个修饰符应该下沉到独立的一行。
正确写法:
function thisFunctionNameIsReallyLong(address x, address y, address z)
public
onlyowner
priced
returns (address)
{
doSomething();
}
function thisFunctionNameIsReallyLong(
address x,
address y,
address z,
)
public
onlyowner
priced
returns (address)
{
doSomething();
}
错误写法:
function thisFunctionNameIsReallyLong(address x, address y, address z)
public
onlyowner
priced
returns (address) {
doSomething();
}
function thisFunctionNameIsReallyLong(address x, address y, address z)
public onlyowner priced returns (address)
{
doSomething();
}
function thisFunctionNameIsReallyLong(address x, address y, address z)
public
onlyowner
priced
returns (address) {
doSomething();
}
八、变量声明
数组变量的声明在变量类型和括号之间不应该有空格。
正确写法:
uint[] x;
错误写法:
uint [] x;
九、其他建议
字符串应该用双引号而不是单引号。
正确写法:
str = "foo";
str = "Hamlet says, 'To be or not to be...'";
错误写法:
str = 'bar';
str = '"Be yourself; everyone else is already taken." -Oscar Wilde';
操作符两边应该各有一个空格。
正确写法:
x = 3;
x = 100 / 10;
x += 3 + 4;
x |= y && z;
错误写法:
x=3;
x = 100/10;
x += 3+4;
x |= y&&z;
为了表示优先级,高优先级操作符两边可以省略空格。这样可以提高复杂语句的可读性。
你应该在操作符两边总是使用相同的空格数:
正确写法:
x = 2**3 + 5;
x = 2*y + 3*z;
x = (a+b) * (a-b);
错误写法:
x = 2** 3 + 5;
x = y+z;
x +=1;
十、命名规范
为了避免混淆,下面的名字用来指明不同的命名方式。
-
b (单个小写字母)
-
B (单个大写字母)
-
lowercase (小写)
-
lower_case_with_underscores (小写和下划线)
-
UPPERCASE (大写)
-
UPPER_CASE_WITH_UNDERSCORES (大写和下划线)
-
CapitalizedWords (驼峰式,首字母大写)
-
mixedCase (混合式,与驼峰式的区别在于首字母小写!)
-
Capitalized_Words_With_Underscores (首字母大写和下划线)
合约和库名称
合约和库名称应该使用驼峰式风格。比如:
SimpleToken,
SmartBank,
CertificateHashRepository,
Player。
结构体名称
结构体名称应该使用驼峰式风格。比如:MyCoin,Position,PositionXY。
事件名称
事件名称应该使用驼峰式风格。比如:Deposit,Transfer,Approval,BeforeTransfer,AfterTransfer。
函数名称
函数名称不同于结构,应该使用混合式命名风格。比如:getBalance,transfer,verifyOwner,addMember,changeOwner。
函数参数命名
函数参数命名应该使用混合式命名风格。比如:initialSupply,account,recipientAddress,senderAddress,newOwner。在编写操作自定义结构的库函数时,这个结构体应该作为函数的第一个参数,并且应该始终命名为 self。
局部变量和状态变量名称
使用混合式命名风格。比如:totalSupply,remainingSupply,balancesOf,creatorAddress,isPreSale,tokenExchangeRate。
常量命名
常量应该全都使用大写字母书写,并用下划线分割单词。比如:MAX_BLOCKS,TOKEN_NAME,TOKEN_TICKER,CONTRACT_VERSION。
修饰符命名
使用混合式命名风格。比如:onlyBy,onlyAfter,onlyDuringThePreSale。
枚举变量命名
在声明简单类型时,枚举应该使用驼峰式风格。比如:TokenGroup,Frame,HashStyle,CharacterLocation。
避免命名冲突
-
single_trailing_underscore_
当所起名称与内建或保留关键字相冲突时,建议照此惯例在名称后边添加下划线。