3.1 保留字
3.2 运算符
优先级
一元运算符优先级最高,二元(两个操作数)则分成五个级别,从高低分别是
二元运算符
除位移操作外,操作数类型必须相同。如果其中一个是无显式类型声明的常量,那么该 常量操作数会自动转型。
位运算符
自增
自增、自减不再是运算符。只能作为独立语句,不能用于表达式。
指针
不能将内存地址与指针混为一谈。
内存地址是内存中每个字节单元的唯一编号,而指针则是一个实体。指针会分配内存空间,相当于一个专门用来保存地址的整型变量。
- 取址运算符“&”用于获取对象地址。
- 指针运算符“*”用于间接引用目标对象。
- 二级指针**T,如包含包名则写成*package.T。
指针类型支持相等运算符,但不能做加减法运算和类型转换。如果两个指针指向同一地 址,或都为nil,那么它们相等。
可通过unsafe.Pointer将指针转换为uintptr后进行加减法运算,但可能会造成非法访问。
Pointer类似C语言中的void*万能指针,可用来转换指针类型。它能安全持有对象或对象成员, 但uintptr不行:后者仅是一种特殊整型,并不引用目标对象,无法阻止垃圾回收器回收对象内存。
指针没有专门指向成员的“->”运算符,统一使用“.”选择表达式。
3.3 初始化
对复合类型(数组、切片、字典、结构体)变量初始化时,有一些语法限制。
- 初始化表达式必须含类型标签。
- 左花括号必须在类型尾部,不能另起一行。
- 多个成员初始值以逗号分隔。
- 允许多行,但每行须以逗号或右花括号结束。
package main
import "fmt"
func main() {
type data struct {
x int
y string
}
var a data = data{1, "s"}
b := data{
1,
"asdf",
}
c := []int{
1,
2,
3,
}
d := []int{1, 2, 3,
4,
5,
}
fmt.Println(a, b, c, d)
}
3.4 流程控制
if
支持初始化语句,可定义块局部变量或执行初始化函数。
func main() {
x := 10
if err := check(x); err != nil {
log.Fatalln(err)
}
x++
println(x)
}
switch
与if语句类似,switch语句也用于选择执行,但具体使用的场景会有所不同。
- switch同样支持初始化语句,按从上到下,从左到右顺序匹配case执行,只有全部匹配失败时才会执行default块
- 考虑到default与else类似,建议将其放在switch末尾
- 相邻的空case不构成多条件匹配
- 不能出现重复的case值:
- 无需显示执行break语句,case执行完毕后制动中断。如需贯通后续case(源码顺序),须执行fallthrough,但不再匹配后续条件表达式
package main
func main() {
switch x := 5; x {
default:
println(x)
case 5:
x += 10
println(x) //15
fallthrough // 继续执行下一case,但不再匹配表达式
case 6:
x += 20
println(x) //35
//fallthrough //cannot fallthrough final case in switch
}
}
- 某些时候,switch语句还被用于替换if语句。被省略的switch条件表达式默认值为true,继而与case比较表达式结果匹配
for
仅有for一种循环语句
for i := 0; i < 3; i++ {
}
for x < 10 { //类似 while x < 10
x++
}
for { //类似while true
break
}
可用for…range完成数据迭代,支持字符串、数组、数组指针、切片、字典、通道类型,返回索引、键值数据
package main
import (
"fmt"
)
func main() {
s := "asdfsdf"
for i, j := range s {
fmt.Println(i, j)
}
a := [3]string{"a", "b", "c"}
for i, j := range a {
fmt.Println(i, j)
}
b := []string{"x", "x", "x", "y"}
for i, j := range b {
fmt.Println(i, j)
}
e, f, g := 1, 2, 3
d := [3]*int{&e, &f, &g}
for i, j := range d {
fmt.Println(i, j)
}
var h = make(map[string]int)
h["a"] = 1
h["b"] = 2
h["c"] = 3
h["d"] = 4
for i, j := range h {
fmt.Println(i, j)
}
}
允许返回单值,或用“_”忽略。
package main
import (
"fmt"
)
func main() {
data := [3]string{"a", "b", "c"}
for i := range data { // 忽略值
fmt.Println(i)
}
for _, j := range data { // 忽略索引
fmt.Println(j)
}
for range data { //仅迭代,不返回。可用来执行清空channel等操作
}
}
goto,continue,break
- goto 使用goto前,须先定义标签。标签区分大小写,且未使用的标签会引发编译错误。
func main() {
for i := 0; i < 3; i++ {
println(i)
if i >= 1 {
goto exit
}
}
exit:
println("exit.")
}
0
1
exit.
不能跳转到其他函数,或内层代码块内
- break: 用于switch、for、select语句,终止,整个语句块执行。
- continue:仅用于for循环,终止后续逻辑,立即进入下一轮循环
配合标签,break,continue可在多层嵌套中指定目标层级
func main() {
outer:
for x := 0; x < 5; x++ {
for y := 0; y < 10; y++ {
if y > 2 {
println()
continue outer
}
if x > 2 {
break outer
}
print(x, ":", y, " ")
}
}
}
结果
0:0 0:1 0:2
1:0 1:1 1:2
2:0 2:1 2:2