代码指导

基本约束

  • 所有应用的 main 包需要有 APP_VER 常量表示版本,格式为 X.Y.Z.Date [Status],例如:0.7.6.1112 Beta
  • 单独的库需要有函数 Version 返回库版本号的字符串,格式为 X.Y.Z[.Date]
  • 当单行代码超过 80 个字符时,就要考虑分行。分行的规则是以参数为单位将从较长的参数开始换行,以此类推直到每行长度合适:

    1. So(z.ExtractTo(
    2. path.Join(os.TempDir(), "testdata/test2"),
    3. "dir/", "dir/bar", "readonly"), ShouldBeNil)
  • 当单行声明语句超过 80 个字符时,就要考虑分行。分行的规则是将参数按类型分组,紧接着的声明语句的是一个空行,以便和函数体区别:

    1. // NewNode initializes and returns a new Node representation.
    2. func NewNode(
    3. importPath, downloadUrl string,
    4. tp RevisionType, val string,
    5. isGetDeps bool) *Node {
    6. n := &Node{
    7. Pkg: Pkg{
    8. ImportPath: importPath,
    9. RootPath: GetRootPath(importPath),
    10. Type: tp,
    11. Value: val,
    12. },
    13. DownloadURL: downloadUrl,
    14. IsGetDeps: isGetDeps,
    15. }
    16. n.InstallPath = path.Join(setting.InstallRepoPath, n.RootPath) + n.ValSuffix()
    17. return n
    18. }
  • 分组声明一般需要按照功能来区分,而不是将所有类型都分在一组:

    1. const (
    2. // Default section name.
    3. DEFAULT_SECTION = "DEFAULT"
    4. // Maximum allowed depth when recursively substituing variable names.
    5. _DEPTH_VALUES = 200
    6. )
    7. type ParseError int
    8. const (
    9. ERR_SECTION_NOT_FOUND ParseError = iota + 1
    10. ERR_KEY_NOT_FOUND
    11. ERR_BLANK_SECTION_NAME
    12. ERR_COULD_NOT_PARSE
    13. )
  • 当一个源文件中存在多个相对独立的部分时,为方便区分,需使用由 ASCII Generator 提供的句型字符标注(示例:Comment):

    1. // _________ __
    2. // \_ ___ \ ____ _____ _____ ____ _____/ |_
    3. // / \ \/ / _ \ / \ / \_/ __ \ / \ __\
    4. // \ \___( <_> ) Y Y \ Y Y \ ___/| | \ |
    5. // \______ /\____/|__|_| /__|_| /\___ >___| /__|
    6. // \/ \/ \/ \/ \/
  • 函数或方法的顺序一般需要按照依赖关系由浅入深由上至下排序,即最底层的函数出现在最前面。例如,下方的代码,函数 ExecCmdDirBytes 属于最底层的函数,它被 ExecCmdDir 函数调用,而 ExecCmdDir 又被 ExecCmd 调用:

    1. // ExecCmdDirBytes executes system command in given directory
    2. // and return stdout, stderr in bytes type, along with possible error.
    3. func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
    4. ...
    5. }
    6. // ExecCmdDir executes system command in given directory
    7. // and return stdout, stderr in string type, along with possible error.
    8. func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
    9. bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
    10. return string(bufOut), string(bufErr), err
    11. }
    12. // ExecCmd executes system command
    13. // and return stdout, stderr in string type, along with possible error.
    14. func ExecCmd(cmdName string, args ...string) (string, string, error) {
    15. return ExecCmdDir("", cmdName, args...)
    16. }
  • 结构附带的方法应置于结构定义之后,按照所对应操作的字段顺序摆放方法:

    1. type Webhook struct { ... }
    2. func (w *Webhook) GetEvent() { ... }
    3. func (w *Webhook) SaveEvent() error { ... }
    4. func (w *Webhook) HasPushEvent() bool { ... }
  • 如果一个结构拥有对应操作函数,大体上按照 CRUD 的顺序放置结构定义之后:

    1. func CreateWebhook(w *Webhook) error { ... }
    2. func GetWebhookById(hookId int64) (*Webhook, error) { ... }
    3. func UpdateWebhook(w *Webhook) error { ... }
    4. func DeleteWebhook(hookId int64) error { ... }
  • 如果一个结构拥有以 HasIsCanAllow 开头的函数或方法,则应将它们至于所有其它函数及方法之前;这些函数或方法以 HasIsCanAllow 的顺序排序。

  • 变量的定义要放置在相关函数之前:

    1. var CmdDump = cli.Command{
    2. Name: "dump",
    3. ...
    4. Action: runDump,
    5. Flags: []cli.Flag{},
    6. }
    7. func runDump(*cli.Context) { ...
  • 在初始化结构时,尽可能使用一一对应方式:

    1. AddHookTask(&HookTask{
    2. Type: HTT_WEBHOOK,
    3. Url: w.Url,
    4. Payload: p,
    5. ContentType: w.ContentType,
    6. IsSsl: w.IsSsl,
    7. })