表达式

关键字

一共有25个关键字,如下:

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

运算符

全部运算符、分隔符,以及其他符号。

+ & += &= && == != ( ) - | -= |= || < <= [ ] * ^ *= ^= <- > >= { } / << /= <<= ++ = := , ; % >> %= >>= -- ! ... . : &^ &^=

运算符优先级(从高到低)

high * / & << >> & &^

+ - | " ^

== != < <= < >=

<-

&&

||

运算符demo:

0110 & 1011 = 0010 与 都为 1。
0110 | 1011 = 1111 或 ⾄至少⼀一个为 1。
0110 ^ 1011 = 1101 异或 只能⼀一个为 1。
0110 &^ 1011 = 0100 清除标志位 计算x&^y 首先我们先换算成2进制 如果ybit位上的数是0则取x上对应位置的值, 如果ybit位上为1则取结果位上取0。

不支持运算符重载。尤其需要注意,"++"、"--" 是语句而非表达式

n := 0
p := &n
// b := n++ // syntax error
// if n++ == 1 {} // syntax error
// ++n // syntax error
n++
*p++ // (*p)++ 两种均可,为了方便,使用前面那种方式

初始化

初始化复合对象,必须使用类型标签,且左大括号必须在类型尾部。

  // var a struct { x int } = { 100 } // syntax error
// var b []int = { 1, 2, 3 } // syntax error
// c := struct {x int; y string} // syntax error: unexpected semicolon or newline
// {
// }
var a = struct{ x int }{100}
var b = []int{1, 2, 3}

初始化值以 "," 分隔。可以分多行,但最后一行必须以 "," 或 "}" 结尾。

  a := []int{
	1,
	2 // Error: need trailing comma before newline in composite literal
}

a := []int{
	1,
	2, // ok
}

b := []int{
	1,
	2 } // ok

控制流

if

  • 可省略条件表达式括号。
  • 支持初始化语句,可定义代码块局部变量。
  • 代码块左大括号必须在条件表达式尾部。
if j:=4;j>5 { //j作为局部变量可以在此范围中使用
    ...
}else if j==5 {
    ...
}else {
    ...
}

for

s := "abc"

for i, n := 0, len(s); i < n; i++ { // 常见的 for 循环,支持初始化语句。
	println(s[i])
}

n := len(s)
for n > 0 { // 替代 while (n > 0) {}
	println(s[n]) // 替代 for (; n > 0;) {}
	n--
}

for { // 替代 while (true) {}
	println(s) // 替代 for (;;) {}
}

循环优化:

func main() {
	s := "abcd"
	for i, n := 0, len(s); i < n; i++ { // 避免多次调⽤用 length 函数。
		fmt.Println(s[i])
	}
}

迭代range

执行类似迭代操作,返回(索引,值)或(键,值)

可与string、array、slice、map、channel联合使用

string 返回:下标 字符

array 返回:下标 元素

slice 返回:下标 元素

map 返回:键 元素

channel 返回:元素

range会复制对象,如果使用引用类型,其底层数据就不会被复制

type wrapper struct {

	x int
}

func main() {
	a := [3]int{0, 1, 2}

	for i, v := range a { // index、value 都是从复制品中取出。
		if i == 0 { // 在修改前,我们先修改原数组。
			a[1], a[2] = 999, 999
			fmt.Println(a) // 确认修改有效,输出 [0, 999, 999]。
		}
		fmt.Println(v)
		a[i] = v + 100 // 使用复制品中取出的 value 修改原数组。
	}

	fmt.Println(a) // 输出 [100, 101, 102]。


	b := []wrapper{{1},{2},{3}}
	for i, v := range b { // index、value 都是从底层中取出。
		if i == 0 { // 在修改前,我们先修改原数组。
			b[1], b[2] = wrapper{999},wrapper{999}
			fmt.Println(a) // 确认修改有效,输出 [0, 999, 999]。
		}
		fmt.Println(v)
		a[i] = v.x + 100 // 使用底层中取出的 value 修改原数组。
	}

	fmt.Println(b) // 输出 [{1} {999} {999}]。
}

switch case

分支表达式可以是任意类型,不限于常量。可省略 break默认自动终止

x := []int{1, 2, 3}
i := 2

switch i {
	case x[1]:
		fmt.Println("a")
	case 1, 3:
		fmt.Println("b")
	default:
    	fmt.Println("c")
    //输出a
}

如需要继续下一分支,可使用 fallthrough,但不再判断条件

x := 10

switch x {
	case 10:
		fmt.Println("a") //输出a
		fallthrough
	case 0:
		fmt.Println("b") //输出b
}

省略条件表达式,可当 if...else if...else 使用。

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 {
        fmt.Println(i)
        i++
        if i > 2 {
            goto BREAK
        }
    }

BREAK:
    fmt.Println("break")
EXIT: // Error: label EXIT defined and not used
}

break 可用于 跳出 forswitchselect

continue 仅能用于 跳出单次for 循环。

参考

Go 边看边练

Q.E.D.


此 生 无 悔 恋 真 白 ,来 世 愿 入 樱 花 庄 。