2.1保留字
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
2.2运算符
位运算演示
fmt.Printf("0110 & 1011 = %v (0010) \n", (0110 & 1011)) // AND 都为 1
fmt.Printf("0110 | 1011 = %v (1111) \n", (0110 | 1011)) // OR 至少一个为 1
fmt.Printf("0110 ^ 1011 = %v (1101) \n", (0110 ^ 1011)) // XOR 只能一个为 1
fmt.Printf("0110 &^ 1011 = %v (0100) \n", (0110 &^ 1011)) // AND NOT 清除标志位
标志位操作
a := 0
a |= 1 << 2 // 0000100:在bit2设置标志位
a |= 1 << 6 // 1000100:在bit6设置标志位
a = a &^ (1 << 6) // 0000100:清除bit6标志位
不支持运算符重载,尤其需要注意,“++”、“–”是语句而非表达式
n:=0
p:=&n
b := n++ //syntax error: unexpected ++ at end of statement
if n++ == 1{} //syntax error: unexpected ==, expecting
++n //syntax error: unexpected ++, expecting
n++
*p++ //(*p)++
没有“~”,取反运算也用“^”
var x uint8 = 1
fmt.Printf("变量x=%08b\n", x)
fmt.Printf("变量^x=%08b\n", ^x)
2.3初始化
初始化复合对象,必须使用类型标签,且左大括号必须在类型尾部
var a = struct{ x int }{100}
var b = []int{1, 2, 3}
初始化值以“,”分隔,可以分多行,但最后一行必须以“,”或“}”结尾
a := []int{
1,
2,
}
b := []int{
1,
2}
2.4控制流
IF
可省略条件表达式括号
支持初始化语句,可定义代码块局部变量
代码块左大括号必须在条件表达式尾部
不支持三元操作符“a > b ? a : b”
x := 0
// if x > 10 // Error: missing condition in if statement
// {
// }
if n := "abc"; x > 0 { // 初始化语句未必就是定义变量,⽐如 println("init") 也是可以的。
println(n[2])
} else if x < 0 { // 注意 else if 和 else 左⼤括号位置。
println(n[1])
} else {
println(n[0])
}
FOR
支持三种循环方式,包括while语法
s := "abc"
//第一种
for i, n := 0, len(s); i < n; i++ { //常见的for循环,支持初始化语句
fmt.Println(s[i])
}
//第二种
n := len(s)
for n > 0 { //替代while(n>0){}
fmt.Println(s[n]) //替代for(;n>0;){}
n--
}
//第三种
for { //替代while(true){}
fmt.Println(s) //替代for(;;){}
}
Range
类似迭代器操作,返回(索引,值)或(键,值),可忽略不想要的返回值,或用“_”这个特殊变量,有四种用法
s := "abc"
//第一种
for i := range s { // 忽略 2nd value,⽀持 string/array/slice/map。
fmt.Println(s[i])
}
// 第二种
for _, c := range s { // 忽略 index。
fmt.Println(c)
}
// 第三种
for range s { // 忽略全部返回值,仅迭代。
fmt.Println("忽略全部返回值,仅迭代")
}
// 第四种
m := map[string]int{"a": 1, "b": 2}
for k, v := range m { // 返回 (key, value)。
fmt.Println(k, v)
}
注意:range会复制对象
a := [3]int{0, 1, 2}
for i, v := range a { // index、value 都是从复制品中取出
if i == 0 { // 在修改前,我们先修改原数组
a[1], a[2] = 999, 999
fmt.Printf("确认修改有效,输出%v \n", a) // 确认修改有效,输出 [0, 999, 999]
}
a[i] = v + 100 // 使⽤复制品中取出的 value 修改原数组
}
fmt.Printf("使⽤复制品中取出的 value 修改原数组 %v \n", a) // 输出 [100, 101, 102]
建议改用引用类型,其底层数据不会被复制
另外两种引⽤类型 map、channel 是指针包装,⽽不像 slice 是 struct
s := []int{1, 2, 3, 4, 5}
for i, v := range s { // 复制 struct slice { pointer, len, cap }。
if i == 0 {
s = s[:3] // 对 slice 的修改,不会影响 range。
s[2] = 100 // 对底层数据的修改。
}
println(i, v)
}
Switch
分支表达式可以是任意类型,不限于常量。可省略 break,默认自动终止
x := []int{1, 2, 3}
i := 2
switch i {
case x[1]:
println("a")
case 1, 3:
println("b")
default:
println("c")
}
如需要继续下⼀分⽀,可使⽤ fallthrough,但不再判断条件
x := 10
switch x {
case 10:
println("a")
fallthrough
case 0:
println("b")
}
省略条件表达式,可当 if…else if…else 使用
x := []int{1, 2, 3}
//第一种
switch {
case x[1] > 0:
println("a")
case x[1] < 0:
println("b")
default:
println("c")
}
//第二种
switch i := x[2]; { // 带初始化语句
case i > 0:
println("a")
case i < 0:
println("b")
default:
println("c")
}
Goto, Break, Continue
支持在函数内 goto 跳转。标签名区分大小写,未使用标签引发错误。
func main() {
var i int
for {
println(i)
i++
if i > 2 {
goto BREAK
}
}
BREAK:
println("break")
//EXIT: // Error: label EXIT defined and not used
}
/*
0
1
2
break
*/
配合标签,break 和 continue 可在多级嵌套循环中跳出
func main() {
L1:
for x := 0; x < 3; x++ {
L2:
for y := 0; y < 5; y++ {
if y > 2 {
continue L2
}
if x > 1 {
break L1
}
fmt.Print(x, ":", y, " ")
}
fmt.Println()
}
/*
0:0 0:1 0:2
1:0 1:1 1:2
*/
}
break 可⽤于 for、switch、select,⽽ continue 仅能⽤于 for 循环
x := 100
switch {
case x >= 0:
if x == 0 {
break
}
fmt.Println(x)
}