格式
格式问题是最具争议但同时也是最无关紧要的。人们可以使用不同的格式风格,但最好不要这么做。如果人们都坚持同一种风格,就不用在这个话题上花费太多时间了。现在的问题是不通过长效的风格指导,如何达到这个乌托邦。
在Go中我们采取了独特的方式,就是让机器来关心大多数的格式问题。gofmt程序(也可以被称为go fmt,工作在程序包级别而不是源代码级别)读入一个Go程序,并输出具有标准缩进和垂直对齐的程序,保留根据需要重新格式化的注释。如果你想知道如何处理一些新的布局情况,运行gofmt;如果这个答案看起来不太对,重新组织你的程序(或者提交一个gofmt的bug),不要跳过它。
作为一个示例,没有必要花费时间将结构体字段中的注释排列。Gifmt将会为你做这些。给出下列声明:
type T struct {
name string // name of the object
value int // its value
}
gofmt将会按列进行排列
type T struct {
name string // name of the object
value int // its value
}
所有在标准程序包中的Go代码都已经通过gofmt排列过。
还是有一些排列的细节。非常简短:
缩进:
我们使用tab进行缩进,同时也是gofmt的默认输出。仅在你必要的时候使用空格键。
行长度:
Go没有行长度的限制。不用担心有打孔卡片溢出。如果感觉一行太长了,把它折成几行并用额外的tab缩进。
括号:
相较于C和JAVA,Go更少地使用括号:控制结构(if, for, switch)并没有在它们的语法中使用括号。同时,操作符的优先级更短更清晰,像
x<<8 + y<<16
的含义以及由空格表明,不像其他语言
注释
Go提供了C风格的/* */块注释和C++风格的//行注释。行注释是规范的;块注释大多出现在程序包的注释中,但是在表达式式中或者注释大量代码行的时候,块注释也是很有用的。
程序——同时又是网络服务器——godoc处理Go源文件来抽取关于包内容的文档。出现在顶层声明之前,并且中间没有换行的注释会随着声明被抽取出来,作为该项的解释性文本。这些注释的本质和风格决定了godoc产生的文档的质量。
每一个包中都有一段包注释,一个位于包子句之前的块注释。对于有多个文件的包,包注释仅仅需要出现在一个文件中,在任何一个文件中都可以。包注释应该介绍包的信息同时提供与整个包相关联的信息。它将首先出现在godoc页面上,并会建立后续的详细文档。
/*
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
如果包很简单,包注释也可以很简洁。
// Package path implements utility routines for
// manipulating slash-separated filename paths.
注释不需要额外的格式,例如星条横幅。生成的输出也许不会最为混合宽度的字体展现。所以不要依赖空格来对齐,godoc就像gofmt一样,会帮你处理好这些。注释是不会被解释的纯文本,所以HTML和其他注解,例如_this_将会被逐字复制。godoc会用不同宽度的字体来对缩进的文本进行一些调整,来适应程序片段。fmt包的包注释用了这种方式取得了很好的效果。
根据上下文环境,godoc也许不会重新格式化注释,所以要确保它们看起来够直接:使用正确的拼写,标点,句子结构并折叠长句等。
在一个程序包中,任何在顶层声明之前的注释都会作为该声明的文档注释。每一个在程序中导出(大写)的变量都应该有文档注释。
文档注释最好作为完整的句子实现,这样可以允许各种自动化展示。第一句话应该作为总结句并以声明的变量名开头。
// Compile parses a regular expression and returns, if successful,
// a Regexp that can be used to match against text.
func Compile(str string) (*Regexp, error) {
如果每一个文本注释开始于描述该项的变量名,输出的godoc就可以用grep来处理。假设你正在寻找能解析正则表达式的函数,但是却忘记了”Compile”方法,你可以运行以下命令:
$ godoc regexp | grep -i parse
如果所有在包内的文档注释以”This function…”开头,’grep’将无法帮助你想起这个函数。但是程序包是以变量名来起始每一个文档注释,你将会看到类似这样的信息,这将会使你回想起你在寻找的东西。
$ godoc regexp | grep parse
Compile parses a regular expression and returns, if successful, a Regexp
parsed. It simplifies safe initialization of global variables holding
cannot be parsed. It simplifies safe initialization of global variables
$
Go的声明语法允许组合声明。单个的文档注释可以介绍一组相关联的常量或者变量。因为展示的是整个声明,这样的注释一般都很肤浅。
// Error codes returned by failures to parse an expression.
var (
ErrInternal = errors.New("regexp: internal error")
ErrUnmatchedLpar = errors.New("regexp: unmatched '('")
ErrUnmatchedRpar = errors.New("regexp: unmatched ')'")
...
)
分组还可以用来展示各项之间的关系,分组同样也可以指明项之间的关系,例如实际上是由一个互斥锁所保护的一组变量。
var (
countLock sync.Mutex
inputCount uint32
outputCount uint32
errorCount uint32
)