【Solidity智能合约系列】11--编码规范

作者: 唠嗑008 | 来源:发表于2018-06-11 16:28 被阅读13次

    前言

    这是Solidity智能合约语言的最后一讲了,这一节主要说说Solidity编码规范的问题。

    代码格式相关

    缩进

    使用使用空格(spaces)而不是Tab,用4个空格来表示缩进。避免混合使用Tab空格

    空白行(Blank Lines)

    合约之间应该有2行空格

    规范的写法

    contract A {
        ...
    }
    
    
    contract B {
        ...
    }
    
    
    contract C {
        ...
    }
    

    不规范的写法:

    contract A {
        ...
    }
    contract B {
        ...
    }
    
    contract C {
        ...
    }
    

    在一个合约的2个函数之间应该有1个空行。例如:

    contract A {
        function spam() public {
            ...
        }
        
        function ham() public {
            ...
        }
    }
    

    没有实现的话,空行可以省去.

    规范的写法:

    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 {
            ...
        }
    }
    

    控制每一行的最大长度(Maximum Line Length)

    控制每一行在79(或者99)个字符以内,方便读者解读代码

    1、第一个参数不应该附加在开头的括号上
    2、应该只使用一个缩进
    3、每个参数应该在单独的一行
    4、这个标识符 );应该放在最后一行

    函数调用

    推荐的方式

    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 Definitions and Event Emitters)

    规范写法:

    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);
    

    源文件编码

    推荐使用UTF-8 或者 ASCII编码

    Imports

    Import语句应该在文件最上方

    推荐使用:

    import "owned";
    
    
    contract A {
        ...
    }
    
    
    contract B is owned {
        ...
    }
    

    不推荐使用:

    contract A {
        ...
    }
    
    
    import "owned";
    
    
    contract B is owned {
        ...
    }
    

    函数规范(Order of Functions)

    函数顺序

    函数排序能够帮助读者识别他们可以调用哪些函数,并且更容易找到构造函数,回退函数

    函数应该根据其可见行和顺序来分组(官方推荐的的函数顺序是)
    1、构造函数
    2、回退函数 (如果有)
    3、外部函数(external)
    4、公有函数(public)
    5、内部函数(internal)
    6、私有函数(private)

    同一类函数,constant函数放在后面。

    推荐的方式:

    contract A {
        // 构造函数
        function A() public {
            ...
        }
    
        // 回退函数
        function() public {
            ...
        }
    
        // 外部函数
        // ...
    
        // 带有constant 外部函数 
        // ...
    
        // 公有函数
        // ...
    
        // 内部函数
        // ...
    
        // 私有函数
        // ...
    }
    

    不推荐的格式:

    contract A {
    
    
        // 外部函数
        // ...
    
        // 公有函数
        // ...
    
        // 内部函数
        // ...
        
        function A() public {
            ...
        }
    
        function() public {
            ...
        }
    
        // 私有函数
        // ...
    }
    

    表达式中的空格

    在以下情形,避免使用没有必要的空格

    一个单行的表达里,在小括号、中括号、大括号里应该避免不必要的空格

    推荐:

    spam(ham[1], Coin({name: "ham"}));
    

    不推荐:

    spam( ham[ 1 ], Coin( { name: "ham" } ) );
    

    下面这种是一个例外,结尾的括号跟在结束的分号后面, 应该加一个空格,推荐使用这种方式:

    function singleLine() public { spam(); }
    

    在逗号、分号之前不应有空格

    推荐:

    function spam(uint i, Coin coin) public;
    

    不推荐:

    function spam(uint i , Coin coin) public ;
    

    在赋值的时候,没有必要为了对齐而添加不必要的空格

    推荐:

    x = 1;
    y = 2;
    long_variable = 3;
    

    不推荐:

    x             = 1;
    y             = 2;
    long_variable = 3;
    

    在回退函数不要包含空格

    推荐:

    function() public {
        ...
    }
    

    不推荐:

    function () public {
        ...
    }
    

    控制结构(Control Structures)

    表示合约定义、函数定义、库定义、结构体定义的大括号,推荐使用方式:

    左括号应该跟定义在一行

    contract Coin {
        struct Bank {
            address owner;
            uint balance;
        }
    }
    

    不推荐:

    contract Coin
    {
        struct Bank {
            address owner;
            uint balance;
        }
    }
    

    控制语句if, else, while, for左括号也应该跟条件控制在一行

    推荐:

    if (...) {
        ...
    }
    
    for (...) {
        ...
    }
    

    不推荐:

    if (...)
    {
        ...
    }
    
    while(...){
    }
    
    for (...) {
        ...;}
    

    如果控制结构的方法体内的语句只有1行,那么大括号是可以省略的。

    推荐:

    if (x < 10)
        x += 1;
    

    不推荐:

    if (x < 10)
        someArray.push(Coin({
            name: 'spam',
            value: 42
        }));
    

    明确函数的可见性

    所有的函数(包括构造函数)应该在定义的时候明确函数的可见性,例如应该使用:

    function explicitlyPublic(uint val) public {
        doSomething();
    }
    

    不推荐:

    function implicitlyPublic(uint val) {
        doSomething();
    }
    

    对于包含有else 或者 else if子句的if语句, else 或者 else if应该放置在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 kill() public onlyowner {
        selfdestruct(owner);
    }
    

    不推荐方式:

    function kill() onlyowner public {
        selfdestruct(owner);
    }
    

    命名规范

    在命名中要避免单独的使用小写的l,大写的I,大写的O。因为这样容易产生混淆,容易和数字01不可区分。

    合约、库(Library)、结构体、事件、枚举的命名

    合约、库、结构体、事件的命名应该使用大驼峰(首字母大写的方式)命名法。例如:SimpleToken, SmartBank, CertificateHashRepository, Player

    函数、函数参数、局部变量、状态变量、修饰器(Modifier)的命名

    除了构造函数以外的函数、函数参数、局部变量、状态变量、修饰器(Modifier)都应该使用小驼峰(mixedCase)命名法。比如:getBalance, transfer, verifyOwner, addMember, changeOwner

    常量

    常量应该使用全大写及下划线分割大词的方式,如:MAX_BLOCKS,TOKEN_NAME, CONTRACT_VERSION。

    区分函数和事件

    为了防止函数和事件(Event)产生混淆,声明一个事件使用大写并加入前缀(可使用LOG)。对于函数, 始终以小写字母开头,构造函数除外。

    // 不建议
    event Transfer() {}
    function transfer() {}
    
    // 建议
    event LogTransfer() {}
    function transfer() external {}
    

    参考:
    https://solidity.readthedocs.io/en/v0.4.23/style-guide.html

    相关文章

      网友评论

        本文标题:【Solidity智能合约系列】11--编码规范

        本文链接:https://www.haomeiwen.com/subject/ktsceftx.html