格式化
golang 提供了gofmt程序(也可以使用go fmt,它以包为处理对象而非源文件)将go程序按照标准风格缩紧、对齐,保留注释兵在需要时重新格式化;
比如,下面程序你无需花时间将结构体中的字段注释对齐,gofmt 会处理的;
type T struct {
name string // name of the object
value int // its value
}
格式化后:
type T struct {
name string // name of the object
value int // its value
}
格式化的细节
- 缩进
我们使用制表符缩进,gofmt 默认也使用它。在你认为确实有必要时再使用空格
- 行的长度
Go 对行的长度没有限制,最好不要大于80个字符
- 括号
控制结构(if for 和switch) 在语法上并不需要圆括号。
注释
- 支持 C 语言风格注释 /* */
- C++ 风格的行注释 //。
行注释更为常用,/**/ 主要用于包的注释,当然也可以在禁用一大段代码时使用。
godoc 既是一个程序,又是一个 Web 服务器,它对 Go 的源码进行处理,并提取包中的文档内容。 出现在顶级声明之前,且与该声明之间没有空行的注释,将与该声明一起被提取出来,作为该条目的说明文档。 这些注释的类型和风格决定了 godoc 生成的文档质量。
每个包都应该包含一段包注释,即放在package 之前。对于包含多个文件的包, 包注释只需出现在其中的任一一个文件中即可。包注释应该在整体上对该包进行介绍,并提供包的相关信息。
在程序中,每个可导出的名称都应该有文档注释。文档注释最好是完整的句子,这样它才能适应各种自动化的展示。第一句应当以被声明的东西开头,并且是单句的摘要。
// Compile parses a regular expression and returns, if successful, a Regexp
// object that can be used to match against text.
func Compile(str string) (regexp *Regexp, err error) {
命名
获取器
不要将Get放到获取器的名字中,既不符合习惯,也没有必要。比如有个名为ower(小写,未导出)的字段,其获取器应当名为Ower(大写,可导出)而非GetOwner。若要提供设置器方法,SetOwner 是个不错的选择。
owner := obj.Owner()
if owner != user {
obj.SetOwner(user)
}
接口名字
- 只有一个方法的接口应该以该方法的名字加上 -er后缀来命名, 如Reader、Writer、Formatter、CloseNotifier等。
- Read、Write、Close、Flush、 String 等都具有典型的签名和意义,除非明确他们的签名和意义,否则不要使用。
驼峰记法
Go 中约定使用驼峰记法 MixedCaps 或 mixedCaps 而非下划线的方式来对单词名称进行命名。
分号
Go 语言也是分号结尾的,只是词法分析器按照简单的规则自动插入分号,我们写代码的适合就不需要手动添加了;这条规则是“如果新行前的最后一个标记为标识符(包括int 和 float64 这类的单词)、数值或者字符串常量之类的基本子面或以下标记之一
break continue fallthrough return ++ – ) }
则词法分析就在最后插入分号。”
- 分号在大括号之前直接省略。
- 不能将控制结构的左大括号放在下一行
for
与C类比
// c for
for init; condition; post {}
// c while
for condition {}
// c for( ;; )
for {}
switch
switch 多个条件相同处理方式,可以用逗号列举
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return f
}
break 搭配标签可以退出循环;
continue 也可以搭配标签,不过必须要要在循环中;
函数
可命名返回结果
- Go的函数的返回结果可被命名,在函数执行的适合会将命名参数初始化其相应的零值。
- 如果没有明确返回,命名参数的当前值就是返回结果。
Defer
- 执行顺序LIFO。
- 求值是在推迟执行时进行,而非在调用推迟函数时。
Data
new 与 make
new : 用来分配内存的内建函数,但是不会初始化内存,只是将内存设置为零值。
make : 只用于创建slice map 和channel ,并返回一个类型为T(而非 *T)的已经初始化(而非零值)的值。
数组
在Go中:
- 数组是值。将一个数组赋予另一个数组会复制其所有元素。
- 将某个数组传入某个函数,它将收到该数组的一个副本而非指针。
- 数组的大小是其类型的一部分。类型[10]int 和 [20]int是不同的类型。
切片
- 切片是对数组的引用。
- 切片的容量可通过内建函数cap获得,它将给出该切片可获取的最大长度。
- 超出容量,会重新分配切片。
- append 可修改slice 的元素,但是切片自身(其运行时数据结构包含指针、长度和容量)是通过值传递的。
map
- 健可以是任何可以支持相等性操作的类型,切片不可以;
- 试图获取不存在的值,返回该类型的零值;
打印
- %d : 十进制
- %x : 十六进制
- %v : 通用格式,打印值
&{7 -2.35 abc def} - %+v : 给值添加上字段名
&{a:7 b:-2.35 c:abc def} - %#v : 完全按照Go语法打印。
&main.T{a:7, b:-2.35, c:“abc\tdef”} - %T : 打印类型