【翻译】更好的编写Go语言 Part.II

更好编写Go语言

作者: koangel 发表于: 2017-06-25 11:32:11

往期链接:

更好的编写Go语言 Part.I

注释(Commentary)

Go语言很贴近C语言这个我之前就有说过,所以在注释上也是非常人性化的,Go本身提供了与C/C++相近的注释方式,例如 大段注释的 /* 注释 */ 以及单行注释的 //,这一切和C都特别贴近。

个人在编写C时习惯在#include的最上方编写一个由大段注释组成的描述信息,类似这样:

/*
    Author: Koangel
    Email: Jackliu100@gmail.com
    Comment: 功能性描述
    Useage: 用法描述
    Copyright: 版权信息
    Version: 1.0.0 beta
*/

以上也非标准的注释块,在C语言中也许在团队中有所谓标准,而在个人行为中并无标准可言,所以俗称你开心就好

而Go是有一套约定或建议的标准方式:

/*
Package regexp implements a simple library for regular expressions.

The syntax of the regular expressions accepted is:

    regexp:
        concatenation { '|' concatenation }
    concatenation:
        { closure }
    closure:
        term [ '*' | '+' | '?' ]
    term:
        '^'
        '$'
        '.'
        character
        '[' [ '^' ] character-ranges ']'
        '(' regexp ')'
*/
package regexp

其含义为让一个较为复杂的包拥有很详细的注释信息,其中主要是针对用法等行为,标准的注释可以帮助godoc提取相关信息并生成有效的文档信息便于查阅,这个很类似C/C++的doxygen以及C#本身的文档生成体系,所以这种标准是好的,可以更快的描述清楚函数的各种参数信息和用法。

注意:如果需要用godoc去提取信息,请按照以上标准方式编写并且写在文件的最上层位置,例如以上实例除描述信息外,其余内容不建议包含中文。

如果这个包特别简单,简单到一句话可以描述,那么请写为:

// Package path implements utility routines for
// manipulating slash-separated filename paths.

注释无既定格式,所以无需格式化,godoc会自动处理并提取注释内的内容,但是由于godoc提取时是以纯文本提取的,所以无论你增加多少html代码也是没用的,而且本身来说也不推荐在注释中增加代码,至于等宽的格式对齐,对注视而言也没什么意义,所以随性就好。

其实我对注释的要求很简单,文字描述清晰且可以阅读(不要就写2个单词妄图让别人去猜测),适合团队的交流。

本身只涉及代码编写,不介绍godoc的具体用法,建议自行搜索。

命名规则(Names)

命名的内容总是非常重的,无论在团队中的地位还是在一个开源项目中,无论如何我们都会认真的去指定一套标准以便每位在维护代码的成员中可以产生一致性,防止出现杂乱无章和无法阅读的代码块,而GO这一点实际上做的很好。

为什么呢?

因为Go是语法强制性的,例如 函数首字母大小写决定了其是否为public函数或private函数,这一点虽然看上去很怪异,但是避免了像c++一般一个类中出现无数publicprivate并且要搞明白什么是protected含义的问题,程序员的入门看上去更加容易。

那我们具体看看命名规则:

包名

包名导入的基本方法非常简单:

import "bytes"

此时可直接用bytes.函数或结构的方式来访问具体的位置,例如bytes.Buffer,而以上演示的是单一包,实际上本人个人较为推荐的方法为:

import (
    "bytes"
    "encoding/base64"
)

因为这样可以更加清晰的导入多个包,而所有包的导入会查询3个位置 GOPATH/src、当前目录下的Vendor目录以及Go/src等目录,当你要导入一个子包时,可以采用上述方法(在VSCode下默认开启goimport为format工具的话,会自动帮你查询并导入指定包,如果该包未使用会自动删除)。

如果上述导入的包未在下面代码中使用,往往Go语言的编译器会提示你错误,这种情况非常好,有效避免了多余的引用,代码更加简洁明了。

而如果你要编写包时注意,一个目录下只能存在一个包名,所有的库要么放入项目的Vendor目录,要么必须放入GOPATH/src下。

覆盖顺序 项目Vendor 优先于 GOPATH/src 优先于 Go/src 安装目录,此点特别注意。

导入的包名具有唯一性,互斥,而我需要导入2个名称略微冲突的包怎么办呢,可以采用以下方法:

import (
    "bytes"
    a "encoding/base64"
    b "gamedecode/base64"
)

而此时访问函数,则需要使用 a.xxxb.xxx 访问指定函数,此类方法可以有效避免冲突。

获取器

其实就像在C++里面一样,不会自动提供获取器,所以Go的推荐方式是,你自己去编写,只要遵循基本的标准即可。
在C++中一般为Get or Set,这个没什么,有工具可以自动生成,实际上当你要大量反射行为时,获取器没啥卵用。
完全在于个人代码编写习惯和项目需求,所以这个看自己吧,一般的GO获取器标准为:

owner := obj.Owner()
if owner != user {
    obj.SetOwner(user)
}

接口名

按照约定,只包含一个方法的接口应当以该方法的名称加上-er后缀或类似的修饰来构造一个施动着名词,如 Reader、Writer、 Formatter、CloseNotifier 等。

诸如此类的命名有很多,遵循它们及其代表的函数名会让事情变得简单。 Read、Write、Close、Flush、 String 等都具有典型的签名和意义。为避免冲突,请不要用这些名称为你的方法命名, 除非你明确知道它们的签名和意义相同。反之,若你的类型实现了的方法, 与一个众所周知的类型的方法拥有相同的含义,那就使用相同的命名。 请将字符串转换方法命名为 String 而非 ToString。

驼峰记法(MixedCaps)

好吧,我本身也没听过驼峰记法,所以本人专门去看一下中文的文档和相关资料,发现就一句话:Go中约定使用驼峰记法 MixedCaps 或 mixedCaps,简单理解就是开头所说,大写开头即为public,小写开头即为private