智能合约最佳实践之Solidity编码规范

本文首发于深刻浅出区块链社区 原文连接:智能合约最佳实践之Solidity编码规范原文已更新,请读者前往原文阅读html

每一门语言都有其相应的编码规范, Solidity 也同样, 下面官方推荐的规范及个人总结,供你们参考,但愿能够帮助你们写出更好规范的智能合约。app

命名规范

避免使用

小写的l,大写的I,大写的O 应该避免在命名中单独出现,由于很容易产生混淆。ide

合约、库、事件、枚举及结构体命名

合约、库、事件及结构体命名应该使用单词首字母大写的方式,这个方式也称为:帕斯卡命名法或大驼峰式命名法,好比:SimpleToken, SmartBank, CertificateHashRepository,Player。函数

函数、参数、变量及修饰器

函数、参数、变量及修饰器应该使用首单词小写后面单词大写的方式,这个方式也称为:(小)驼峰式命名法,是一种混合大小写的方式,如:学习

  • 函数名应该如:getBalance,transfer,verifyOwner,addMember。
  • 参数和变量应该如:initialSupply,senderAddress,account,isPreSale。
  • 修饰器应该如:onlyAfter,onlyOwner。

代码格式相关

缩进

使用空格(spaces)而不是Tab, 缩进应该是4个空格区块链

空行

合约之间应该有空行,例如:ui

contract A {
    ...
}
    
    
contract B {
    ...
}
    
    
contract C {
    ...
}
复制代码

而不是使用:this

contract A {
    ...
}
contract B {
    ...
}
    
contract C {
    ...
}
复制代码
  • 函数之间应该有空行,例如:
contract A {
    function spam() public {
        ...
    }
    
    function ham() public {
        ...
    }
}
复制代码

没有实现的话,空行能够省去,如:编码

contract A {
    function spam() public; function ham() public; } 复制代码

而不是:spa

contract A {
    function spam() public {
        ...
    }
    function ham() public {
        ...
    }
}
复制代码

左括号应该跟定义在一行

定义包括合约定义、函数定义、库定义、结构体定义等等,例如推荐使用:

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 (...) {
    ...;}
复制代码

若是控制语句内只有一行,括号可省略,如:

if (x < 10)
    x += 1;
复制代码

但像下面一个语句有多方就不能省略,如:

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

表达式内的空格

  • 一个单行的表达里,在小括号、中括号、大括号里应该避免没必要要的空格,例如推荐使用:

    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 {
        ...
    }
    复制代码

控制每一行长度

每行不该该太长,最好在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);
复制代码

文件编码格式

推荐使用utf-8 及 ASCII 编码

引入文件应该在最上方

建议使用:

import "owned";


contract A {
    ...
}


contract B is owned {
    ...
}
复制代码

而不是:

contract A {
    ...
}


import "owned";


contract B is owned {
    ...
}
复制代码

函数编写规范

函数的顺序

在编写函数的时候,应该让你们容易找到构造函数,回退函数,官方推荐的的函数顺序是:

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

    // 私有函数
    // ...
}
复制代码

明确函数的可见性

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

function explicitlyPublic(uint val) public {
    doSomething();
}
复制代码

而不是

function implicitlyPublic(uint val) {
    doSomething();
}
复制代码

可见性应该在修饰符前面

函数的可见性应该写在自定义的函数修饰符前面,例如:

function kill() public onlyowner {
    selfdestruct(owner);
}
复制代码

而不是

function kill() onlyowner public {
    selfdestruct(owner);
}
复制代码

区分函数和事件

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

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

// 建议
event LogTransfer() {}
function transfer() external {}
复制代码

常量

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

参考视频

咱们也推出了目前市面上最全的视频教程:深刻详解以太坊智能合约语言Solidity 目前咱们也在招募课程体验师,能够点击连接了解。

参考文献

Solidity style-guide

深刻浅出区块链 - 系统学习区块链,打造最好的区块链技术博客。

☛ 个人知识星球为各位解答区块链技术问题,欢迎加入讨论。

☛ 关注公众号“深刻浅出区块链技术”第一时间获取区块链技术信息。

相关文章
相关标签/搜索