携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
前言
本系列的文章是写给刚开始学习 Go 这门语言的朋友的(但也并不是入门教学),需要你已经看过了 A Tour of Go 官方教程,或者通过其他网站了解了 Go 的基本语法。本系列文章的目的在于记录、分享一些 Go 语言中较为特殊的语法或用法,起一个裨补缺漏的作用。
这里也把本系列文章引用的文档放在下面:
你也可以在中文网站中找到对应的文档:
Go 的特殊语法
注释
出现在顶级声明之前,且与该声明之间没有空行的注释,将与该声明一起被 godoc 提取出来,作为文档注释。应当注意的是,在程序中每个可导出的名称都应该有文档注释。
命名
Go 约定使用驼峰命名法,并且 Go 中的名称会影响到语义。某个名称在包外是否可见,就取决于其首个字母是否为大写字母。因此,应将导出名的首字母大写,而私有名称的首字母小写。
分号
Go 的词法分析器会按照规则来自动插入分号,规则如下:
若在新行前的最后一个标记为标识符(包括 int 和 float64 这类的单词)、数值或字符串常量之类的基本字面或 break continue fallthrough return ++ -- ) } 之一。
则词法分析将始终在该标记后面插入分号。
所以你不能将 if、for、switch 或 select 的左大括号放到下一行去,否则就会产生错误。像下面这样:
if i < f() // 这里会被加一个分号
{
g()
}
不过,语法分析器会检测出来该问题并报错。
声明与初始化
常量不能用 := 来声明。
声明时未初始化的变量会被赋以零值 0, false, "", nil。
赋值
Go 中多变量可以使用平行赋值,例如用 a, b = b, a 来交换 a 和 b 的值,
或者在循环的条件中使用如下语句 i, j = i+1, j+1。
:= 的再次赋值
在Go中,可用 := 来声明并初始化变量。由于同一作用域中不能对同一变量重复声明,一般情况下 := 不能对已声明的变量再次使用。
但是当满足下列条件时,已被声明的变量 v 可重复出现在 := 声明中:
- 本次声明与已声明的
v处于同一作用域; - 将要赋给
v的值与v已有类型相同; - 在此次声明中至少另有一个变量是新声明的。
例如:
f, err := os.Open(name)
d, err := f.Stat()
此外,这个特性也常被用于较长的 if-else 语句链中。
流程控制
if & switch
if 和 switch 语句可以在条件语句之前,添加初始化语句来设置局部变量。
if i:=f(); i > 0 {
fmt.Println(i)
}
switch i:=f(); i {
case 0:
fmt.Println(0)
case 1, 2, 3, 4:
fmt.Println(i)
default:
fmt.Println("value > 4")
}
switch 语句只会运行选定的 case,而非之后所有的 case。 实际上,Go 自动提供了每个 case 后面所需的 break 语句。 除非以 fallthrough 语句结束,否则分支会自动终止。
另一点重要的不同在于 case 的条件可以为任意类型量,并且可通过逗号分隔来列举相同的处理条件。
没有条件的 switch 同 switch true 一样,这种形式能将一长串 if-else 链写得更加清晰。
break/continue + label
除了 goto 外, break 和 continue 同样可以通过后面加标签语句来跳出多层循环或继续外层循环,一般会把标签顶头写在循环的上一空行中。
walk:
for {
for {
break walk
}
}
相比于在其他语言中可能不推荐使用 goto 以免使程序逻辑混乱;在 Go 中,可能会更建议你无论是否是多层循环,当循环内部代码比较长时(例如大于100行),最好都给循环打上标签,并使用 break 或 continue 加标签的形式来退出或继续循环,这样反而能使程序逻辑更加清晰。
defer
defer 语句会将函数推迟到外层函数返回之后执行。
推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。
推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
for
range 语句可以用来解析 utf-8 字符,这对于遍历获取字符串内容是非常有用的。
另外,Go 没有逗号操作符,而 ++ 和 -- 是语句而不是表达式。 如果你想要在 for 中使用多个变量,应采用平行赋值的方式 (因为它会拒绝 ++ 和 --)
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
结构体
如果我们有一个指向结构体的指针 x,那么可以通过 (*x).f 来访问其字段 f。不过这么写太啰嗦了,所以 Go 也允许我们使用隐式间接引用,直接写 x.f 就可以。