Go语法规范

Go语法规范

go的格式化

go提供了格式化的命令工具gofmt 和go fmt

gofmt

包级别下的格式化

1
2
3
4
5
6
7
8
9
10
usage: gofmt [flags] [path ...]
-cpuprofile string
write cpu profile to this file
-d display diffs instead of rewriting files
-e report all errors (not just the first 10 on different lines)
-l list files whose formatting differs from gofmt's
-r string
rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')
-s simplify code
-w write result to (source) file instead of stdout

如果我想格式化go包目录下的文件,执行

1
gofmt -l -w $GOPATH/src

-l是显示出所有修改的文件,如果要显示修改的diff差异,则需要加上-d

go fmt

多了一个空格,这个go fmt会将此包下的任何.go文件进行格式化

比如在hello下有一个hello.go文件

1
2
3
4
5
➜  hello git:(master) ✗ pwd
/Users/toto/go/src/github.com/golang/example/hello
➜ hello git:(master) ✗ tree
.
└── hello.go

则只需要执行go fmt即可格式化文件。

go commentary(注释)

go提供了/* */块注释和//行注释

godoc 命令可以提取出文件中的注释文档。所以好的注释决定了文档的质量。

  • 每个包都应该有个包注释,在package之前应该有注释
  • 多个包只有一个文件有注释就可以

包注释之下,应该是doc注释,最好是用//来表示doc注释,如方法之前的注释、变量之前的注释。

生成注释

利用go doc命令 生成注释

1
go doc -all <package name>

生成的注释如下

1
2
3
4
5
6
7
8
package stringutil // import "user/stringutil"

this package is stringutils

FUNCTIONS

func Reverse(s string) string
everse returns its argument string reversed rune-wise left to right.

包注释下是分组注释如方法则以FUNCTIONS开头等

names 命名

go的名称的和其他的语言一样重要,包外可见性取决于名称是否为大小。所以应该好好学习一下。

###包名

通常情况下包名应该:

  • 小写
  • 单个单词
  • 包名应该和文件名一样,如encoding/base64的包名应该是 base64

get set

最好不要是用getxxx(),应该使用大写的Xxxx()

set可以Setxxx()

接口名字

接口如果只含有一个方法应当写成xxxer()加上-er后缀。

Semicolons 分号

go会在以下位置自动加上分号,不用手动处理

1
break continue fallthrough return ++ -- ) }

不能像C#一样把{}另起一行来,因为如果这样的话会在大括号前面加上一个;可能引起不必要的麻烦。

Control structures 控制结构

if语句

if语句支持初始化条件并且没有大括号:eg

1
2
3
4
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}

for循环

for循环没有括号,但是条件并且同样用;来进行区分

1
2
3
4
5
6
7
8
// 如同C的for循环
for init; condition; post { }

// 如同C的while循环
for condition { }

// 如同C的for(;;)循环
for { }

如果想遍历一个数组、切片、字符串或者映射可以用range来做遍历.

1
2
3
for key, value := range oldMap {
newMap[key] = value
}

如果只想遍历第一个元素,下标或者key,那么可以去掉第二个元素

1
2
3
4
5
for key := range m {
if key.expired() {
delete(m, key)
}
}

如果只想遍历第二个,可以用blank identifier空白标识符

1
2
3
4
sum := 0
for _, value := range array {
sum += value
}

并且range支持UTF-8,可以将Unicode分离出来,如中文。

tip:如果想再for循环里使用++,放弃吧,在上面说到++ 会将其变为一句话(因为会加上分号)因此用+1,-1的形式比较好

Switch语句

如果想用if else的结构的话,最好使用switch

1
2
3
4
5
6
7
8
9
10
11
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}

switch没有break,因此相同的条件用,来区分

1
2
3
4
5
6
7
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}

打破switch和循环

我们可以使用break来打破此次switch,并且用break Loop来打破循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Loop:
for n := 0; n < len(src); n += size {
switch {
case src[n] < sizeOne:
if validateOnly {
break
}
size = 1
update(src[n])

case src[n] < sizeTwo:
if n+1 >= len(src) {
err = errShortInput
break Loop
}
if validateOnly {
break
}
size = 2
update(src[n] + src[n+1]<<shift)
}
}

Continue

在go中也游泳,但是只用在循环当中。

谢谢您的鼓励~