Golang 学习之路五:表达式

来源:互联网 发布:绘图软件下载 编辑:程序博客网 时间:2024/06/09 22:18

Golang学习表达式

一、保留字

  Go语言规定了特定的字符序列,它们被称为关键字,又叫作保留字。我们不能把关键字作为标识符使用。
  这里写图片描述

二、运算符

  运算符是一个符号,通知编译器执行数学或逻辑操作。Go语言有丰富的内置运算符,可分为以下几类:

分类 运算符 说明 算数运算符 +,-,*,,%,++,- - 基本与C相同,注意++和- -只是语句并不是表达式,不能把它直接赋值其他变量,b:=a++是错误的 关系运算符 ==,!=,>,<,>=,<= 用法基本与C相同 逻辑运算符 &&,!,ll 用法基本与C相同 按位运算符 &,l,^,<<,>> 用法基本与C相同 赋值运算符 =,+=,-=,*=,/=,%=,<<=,>>=,&=,^=,l= 用法基本与C相同 其它运算符 *,& *指向变量的指针,&返回变量的地址

三、初始化

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

// 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

四、控制流

1. IF

  • 可以省略条件表达式的括号。
  • 支持初始化语句,可以定义代码块局部变量。
  • 代码块左大括号必须在条件表达式尾部。
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])}
  • 不支持三元操作符 如: a > b ? a : b

2. For

  支持三种循环方式,包括类 while 语法的用法。

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 (;;) {}}

输出结果

call length.0 971 982 993 100

3. Range

  • 类似迭代器的操作,返回(索引,值)或(键,值)。
1st value 2nd value string index s[index] unicode.rune array/slice index s[index] map key m[key] channel element
  • 可忽略不想要的返回值,或用”_”这样的特殊变量。
s := "abc"for i := range s { // 忽略 2nd value,⽀支持 string/array/slice/map。    println(s[i])}for _, c := range s { // 忽略 index。    println(c)}for range s { // 忽略全部返回值,仅迭代。...}m := map[string]int{"a": 1, "b": 2}for k, v := range m { // 返回 (key, value)。    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.Println(a) // 确认修改有效,输出 [0, 999, 999]。    }    a[i] = v + 100 // 使⽤用复制品中取出的 value 修改原数组。}fmt.Println(a) // 输出 [100, 101, 102]。
  • 使用引用类型,其底层数据不会被复制。
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)}

输出

0 11 22 1003 44 5
  • 另外两种引用类型 map、channel是指针包装,slice是struct。

4. Switch

  • 分支表达式可以是任意类型,不限于常量。可以省略break,默认自动停止。
x := []int{1, 2, 3}i := 2switch i {    case x[1]:        println("a")    case 1, 3:        println("b")    default:        println("c")}

输出:

a  //注意,case 1,3是或
  • 要继续下一分支,可以使用fallthrough,但不再判断条件。
    x := []int{1, 2, 3}    i := 2    switch i {    case x[1]:        fmt.Println("a")        fallthrough    case 2, 3:        fmt.Println("b")    default:        fmt.Println("c")    }

输出结果:

ab
  • 省略条件表达式,可当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")}

5. 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}
  • 配合标签breakcontinue可在多级嵌套循环中跳出。
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            }            print(x, ":", y, " ")        }        println()    }}

注意:break可以for、switch、select,而continue仅能用于for循环。

func main() {    x := 100    switch {    case x >= 0:        if x == 0 {            break        }        println(x)    }}

五、补充:select

  select是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。select随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。

select {    case communication clause  :       statement(s);          case communication clause  :       statement(s);     /* 你可以定义任意数量的 case */    default : /* 可选 */       statement(s);}

以下描述了 select 语句的语法:

  • 每个case都必须是一个通信
  • 所有channel表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行;其他被忽略。
  • 如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。
    否则:
    • 如果有default子句,则执行该语句。
    • 如果没有default字句,select将阻塞,直到某个通信可以运行
    • Go不会重新对channel或值进行求值。

示例

package mainimport "fmt"func main() {    var c1, c2, c3 chan int    var i1, i2 int    select {    case i1 = <-c1:        fmt.Printf("received ", i1, " from c1\n")    case c2 <- i2:        fmt.Printf("sent ", i2, " to c2\n")    case i3, ok := (<-c3): // same as: i3, ok := <-c3        if ok {            fmt.Printf("received ", i3, " from c3\n")        } else {            fmt.Printf("c3 is closed\n")        }    default:        fmt.Printf("no communication\n")    }}

输出结果:

no communication

六、总结

  本部分简要介绍了保留字、运算符、表达式的初始化和控制流,最后补充了select控制流。熟悉这些用法,注意与C语言语法差异之处。

参考资料

  1. Go 语言第一课
  2. Go 学习笔记(雨痕)
  3. Go 官网教程 Tour
  4. Go 语言教程
0 0