Golang 学习之路五:表达式

Golang学习表达式

一、保留字

  Go语言规定了特定的字符序列,它们被称为关键字,又叫作保留字。我们不能把关键字作为标识符使用。
  Golang 学习之路五:表达式_第1张图片

二、运算符

  运算符是一个符号,通知编译器执行数学或逻辑操作。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 97
1 98
2 99
3 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 1
1 2
2 100
3 4
4 5
  • 另外两种引用类型 map、channel是指针包装,slice是struct。

4. Switch

  • 分支表达式可以是任意类型,不限于常量。可以省略break,默认自动停止。
x := []int{1, 2, 3}
i := 2
switch 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")
    }

输出结果:

a
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")
}

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 main

import "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 语言教程

你可能感兴趣的:(Golang,学习之路,golang)