Post

Day03(运算符与条件语句)

运算符

在 Go 语言(又称 Golang)中,并没有直接列出所有可能的运算法种类,因为运算法(或称为运算符)是编程语言的内置特性,用于执行不同类型的计算或逻辑操作。但是,我们可以分类列出 Go 语言中常用的运算法种类:

  1. 算术运算符

    • 加法 (+)
    • 减法 (-)
    • 乘法 (*)
    • 除法 (/)
    • 整除(取整)(%%%,在某些情况下)
    • 自增 (++)
    • 自减 (--)
  2. 关系运算符(或比较运算符):

    • 等于 (==)
    • 不等于 (!=)
    • 大于 (>)
    • 小于 (<)
    • 大于等于 (>=)
    • 小于等于 (<=)
  3. 逻辑运算符

    • 逻辑与 (&&)
    • 逻辑或 (||)
    • 逻辑非 (!)
  4. 位运算符

    • 位与 (&)
    • 位或 (|)
    • 位异或 (^)
    • 位与非 (&^)
    • 左移 (<<)
    • 右移 (>>)
    • 无符号右移 (>>>,但 Go 中没有无符号右移运算符)
  5. 赋值运算符

    • 赋值 (=)
    • 复合赋值(例如 +=-=*=/= 等)
  6. 其他运算符

    • 地址运算符 (& 用于获取变量的地址,但在赋值上下文中作为位与运算符)
    • 指针解引用 (* 用于解引用指针)
    • 长度和容量运算符 (len()cap(),它们不是真正的运算符,但常用于数组、切片、映射和通道)
    • 索引和切片 ([],用于数组、切片和字符串的索引或切片操作)
    • 通道运算符 (<-,用于发送和接收通道的数据)
  7. 类型断言和类型转换

    • 类型断言 (v, ok := i.(T),用于接口到具体类型的断言)
    • 类型转换 (T(v),用于将一个类型的值转换为另一个类型)

算术运算符

算术运算符在 Go 语言中用于执行数学计算。以下是 Go 语言中算术运算符的列表,每个运算符都附有描述和示例:

运算符 描述 示例
+ 加法,将两个数相加 a := 5 + 3 // a = 8
- 减法,从第一个数中减去第二个数 b := 5 - 3 // b = 2
* 乘法,将两个数相乘 c := 5 * 3 // c = 15
/ 除法,将第一个数除以第二个数 d := 10 / 3 // d = 3(整数除法,结果为整数部分)
% 取模(求余),返回两个数相除的余数 e := 10 % 3 // e = 1
++ 自增,将变量的值增加 1(前缀或后缀) f := 5; f++; // f = 6
g := 5; ++g; // g = 6
-- 自减,将变量的值减少 1(前缀或后缀) h := 5; h--; // h = 4
i := 5; --i; // i = 4

请注意,在 Go 语言中,整数除法会向下取整(即”截断”小数部分),因此 10 / 3 的结果是 3 而不是 3.333...。如果你需要浮点数的除法结果,你应该至少有一个操作数是浮点数,如 10.0 / 3float64(10) / 3

此外,++-- 运算符既可以作为前缀运算符(如 ++i),也可以作为后缀运算符(如 i++)。前缀运算符会先增加或减少变量的值,然后再返回新值;后缀运算符会先返回原始值,然后再增加或减少变量的值。这在循环和迭代中特别有用,但使用时需要小心以避免意外的副作用。

  • 完整例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import "fmt"

func main() {
    // 定义两个整数变量
    var num1, num2 int

    // 初始化这两个变量
    num1 = 10
    num2 = 3

    // 计算两个数的和
    sum := num1 + num2
    fmt.Println("Sum:", sum) // 输出: Sum: 13

    // 计算两个数的差
    difference := num1 - num2
    fmt.Println("Difference:", difference) // 输出: Difference: 7

    // 计算两个数的积
    product := num1 * num2
    fmt.Println("Product:", product) // 输出: Product: 30

    // 计算两个数相除的商(整数除法)
    quotient := num1 / num2
    fmt.Println("Quotient:", quotient) // 输出: Quotient: 3

    // 计算两个数相除的余数
    remainder := num1 % num2
    fmt.Println("Remainder:", remainder) // 输出: Remainder: 1

    // 使用自增运算符增加 num1 的值
    num1++
    fmt.Println("num1 after increment:", num1) // 输出: num1 after increment: 11

    // 使用自减运算符减少 num2 的值
    num2--
    fmt.Println("num2 after decrement:", num2) // 输出: num2 after decrement: 2

    // 合并使用算术运算符来计算一个表达式的值
    // 这里我们计算 (num1 + num2) * num2 - num1 的值
    combinedResult := (num1 + num2) * num2 - num1
    fmt.Println("Combined Result:", combinedResult) // 输出: Combined Result: 20
}

关系运算符(或比较运算符)

关系运算符(或比较运算符)用于比较两个操作数的大小或是否相等。以下是关系运算符的表格形式,以及每个运算符的示例:

运算符 描述 示例
== 等于 a := 5; b := 5; fmt.Println(a == b) // 输出: true
!= 不等于 a := 5; b := 3; fmt.Println(a != b) // 输出: true
> 大于 a := 5; b := 3; fmt.Println(a > b) // 输出: true
< 小于 a := 3; b := 5; fmt.Println(a < b) // 输出: true
>= 大于或等于 a := 5; b := 5; fmt.Println(a >= b) // 输出: true
<= 小于或等于 a := 3; b := 5; fmt.Println(a <= b) // 输出: true
  • 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import "fmt"

func main() {
    // 示例:使用 == 运算符
    a := 5
    b := 5
    fmt.Println("a == b:", a == b) // 输出: a == b: true

    // 示例:使用 != 运算符
    c := 5
    d := 3
    fmt.Println("c != d:", c != d) // 输出: c != d: true

    // 示例:使用 > 运算符
    e := 7
    f := 5
    fmt.Println("e > f:", e > f) // 输出: e > f: true

    // 示例:使用 < 运算符
    g := 3
    h := 7
    fmt.Println("g < h:", g < h) // 输出: g < h: true

    // 示例:使用 >= 运算符
    i := 5
    j := 5
    fmt.Println("i >= j:", i >= j) // 输出: i >= j: true

    // 示例:使用 <= 运算符
    k := 3
    l := 5
    fmt.Println("k <= l:", k <= l) // 输出: k <= l: true
}

逻辑运算符

假定 A 值为 True,B 值为 False。

运算符 描述 实例
&& 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 (A && B) 为 False
|| 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 (A|| B) 为 True
! 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 !(A && B) 为 True
  • 例子 以下是逻辑运算符的表格形式,以及每个运算符的示例:
运算符 描述 示例(假设 atruebfalse    
&& 逻辑与(AND) 如果 a && b,则结果为 false(因为 bfalse    
`   ` 逻辑或(OR) 如果 a | | b,则结果为 true(因为 atrue
! 逻辑非(NOT) 如果 !a,则结果为 false(因为 atrue,取反后为 false    

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
 "fmt"
)

func main() {
 a := true
 b := false

 // 逻辑与(AND)
 andResult := a && b
 fmt.Println("a && b:", andResult) // 输出: a && b: false

 // 逻辑或(OR)
 orResult := a || b
 fmt.Println("a || b:", orResult) // 输出: a || b: true

 // 逻辑非(NOT)
 notResultA := !a
 notResultB := !b
 fmt.Println("!a:", notResultA) // 输出: !a: false
 fmt.Println("!b:", notResultB) // 输出: !b: true
}

在这个示例中,我们定义了两个布尔变量 ab,分别赋值为 truefalse。然后,我们使用逻辑运算符 &&||! 对这两个变量进行运算,并将结果打印出来。逻辑与 && 的结果只有在两个操作数都为 true 时才为 true,逻辑或 || 的结果只要有一个操作数为 true 就为 true,逻辑非 ! 则是对一个布尔值取反。

位运算符

  • 直观例子
p q p & q p| q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
  • 解释

    运算符 描述 示例(假设 a = 60, b = 13,均为二进制表示)
    & 位与(AND) a = 0011 1100(60)
    b = 0000 1101(13)
    a & b = 0000 1100(12)
    | 位或(OR) a = 0011 1100(60)
    b = 0000 1101(13)
    a | b = 0011 1101(61)
    ^ 位异或(XOR) a = 0011 1100(60)
    b = 0000 1101(13)
    a ^ b = 0011 0001(49)
    &^ 位清零(AND NOT) a = 0011 1100(60)
    b = 0000 1101(13)
    a &^ b = 0011 0000(48)
    << 左移 a = 0011 1100(60)
    a « 2 = 1111 0000(240)
    >> 右移 a = 0011 1100(60)
    a » 2 = 0000 1111(15)
    • &(位与):对于每一个二进制位,只有当两个相应的二进制位都为 1 时,结果位才为 1。
    • |(位或):对于每一个二进制位,只要两个相应的二进制位中有一个为 1 时,结果位就为 1。
    • ^(位异或):对于每一个二进制位,当两个相应的二进制位相异时,结果位为 1。
    • &^(位清零):对于每一个二进制位,第一个操作数中与第二个操作数相应位为 1 的位清零。
    • <<(左移):将第一个操作数的所有位向左移动指定的位数,右边用 0 填充。
    • >>(右移):将第一个操作数的所有位向右移动指定的位数,对于无符号整数,左边用 0 填充;对于有符号整数,符号位(最高位)会被复制以保持符号不变。
  • 例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
 var a, b int = 60, 13

    // 位与
    fmt.Printf("a & b = %d\n", a&b) // 输出: a & b = 12

    // 位或
    fmt.Printf("a | b = %d\n", a|b) // 输出: a | b = 61

    // 位异或
    fmt.Printf("a ^ b = %d\n", a^b) // 输出: a ^ b = 49

    // 位清零
    fmt.Printf("a &^ b = %d\n", a&^b) // 输出: a &^ b = 48

    // 左移
    fmt.Printf("a << 2 = %d\n", a<<2) // 输出: a << 2 = 240

    // 右移
    fmt.Printf("a >> 2 = %d\n", a>>2) // 输出: a >> 2 = 15

}

赋值运算符

  • 赋值运算符表格
运算符 描述 示例(Go 风格)
= 简单的赋值运算符,将右侧操作数的值赋给左侧操作数 a = 5
+= 加法赋值运算符(Go 中需要显式写出) a += 3 相当于 a = a + 3
-= 减法赋值运算符(Go 中需要显式写出) b -= 2 相当于 b = b - 2
*= 乘法赋值运算符(Go 中需要显式写出) c *= 4 相当于 c = c * 4
/= 除法赋值运算符(Go 中需要显式写出) d /= 2 相当于 d = d / 2
%= 取模赋值运算符(Go 中需要显式写出) e %= 3 相当于 e = e % 3
  • 例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

func main() {
    // 使用基本赋值运算符
    a := 5
    fmt.Println("a =", a) // 输出: a = 5

    // 使用复合赋值运算符的Go风格(显式写出完整操作)
    a += 3  // 相当于 a = a + 3
    fmt.Println("a += 3, a =", a) // 输出: a += 3, a = 8

    b := 10
    b -= 2  // 相当于 b = b - 2
    fmt.Println("b -= 2, b =", b) // 输出: b -= 2, b = 8

    c := 2
    c *= 4  // 相当于 c = c * 4
    fmt.Println("c *= 4, c =", c) // 输出: c *= 4, c = 8

    d := 10
    d /= 2  // 相当于 d = d / 2
    fmt.Println("d /= 2, d =", d) // 输出: d /= 2, d = 5

    e := 9
    e %= 3  // 相当于 e = e % 3
    fmt.Println("e %= 3, e =", e) // 输出: e %= 3, e = 0
}

其他运算符

运算符 描述 实例
& 返回变量存储地址 &a; 将给出变量的实际地址。
* 指针变量。 *a; 是一个指针变量

条件语句

if& if-else

在 Go 语言中,条件语句主要用于基于不同条件执行不同的代码块。最常用的条件语句是if语句,以及与之相关的elseelse if子句。以下是条件语句的表格形式和例子:

  • 条件语句
语句 描述 示例
if 如果条件为真,则执行代码块 if a > b { ... }
if ... else 如果条件为真,执行第一个代码块;否则执行第二个代码块 if a > b { ... } else { ... }
if ... else if ... else 根据多个条件执行不同的代码块 if a > b { ... } else if a < b { ... } else { ... }
  • 例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package main

import "fmt"

func main() {
    a := 10
    b := 5

    // 基本的if语句
    if a > b {
        fmt.Println("a大于b")
    }
    // 输出: a大于b

    // if ... else语句
    if a < b {
        fmt.Println("a小于b")
    } else {
        fmt.Println("a不小于b")
    }
    // 输出: a不小于b

    // if ... else if ... else语句
    c := 3
    if a > b && a > c {
        fmt.Println("a最大")
    } else if b > a && b > c {
        fmt.Println("b最大")
    } else if c > a && c > b {
        fmt.Println("c最大")
    } else {
        fmt.Println("a、b和c相等或无法判断最大者")
    }
    // 输出: a最大

    // 可以在if语句中使用逻辑运算符组合多个条件
    d := 15
    if d%2 == 0 && d%3 == 0 {
        fmt.Println("d是6的倍数")
    } else {
        fmt.Println("d不是6的倍数")
    }
    // 输出: d不是6的倍数(因为15是3的倍数但不是6的倍数)
}

switch

switch 语句有多种写法,可以用来简化条件判断。以下是一些常见的写法及其示例:

基本 switch 语句

基本的 switch 语句用于依次检测表达式的值,匹配到的值执行对应的代码块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
    x := 2
    switch x {
    case 1:
        fmt.Println("One")
    case 2:
        fmt.Println("Two")
    default:
        fmt.Println("Other")
    }
}

解释:根据 x 的值,匹配相应的 case 并执行其代码块。如果 x 是 2,输出 “Two”。

switch 语句带条件表达式

switch 可以在每个 case 中使用条件表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
    x := 10
    switch {
    case x < 0:
        fmt.Println("Negative")
    case x == 0:
        fmt.Println("Zero")
    case x > 0:
        fmt.Println("Positive")
    }
}

解释:switch 不带表达式,通过 case 条件来匹配,输出 “Positive”。

switch 语句带初始化语句

switch 语句可以包含一个初始化语句,在 switch 表达式之前执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
    switch x := 2 * 3; x {
    case 1, 2, 3:
        fmt.Println("One, Two, or Three")
    case 4, 5, 6:
        fmt.Println("Four, Five, or Six")
    default:
        fmt.Println("Other")
    }
}

解释:先执行初始化语句 x := 2 * 3,然后根据 x 的值进行匹配并执行相应的代码块,输出 “Four, Five, or Six”。

switch 语句的 fallthrough 关键字

fallthrough 关键字用于强制执行下一个 case 块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

func main() {
    x := 1
    switch x {
    case 1:
        fmt.Println("One")
        fallthrough
    case 2:
        fmt.Println("Two")
        fallthrough
    case 3:
        fmt.Println("Three")
    default:
        fmt.Println("Other")
    }
}

解释:x 是 1,先匹配到第一个 case 并输出 “One”,然后 fallthrough 强制执行下一个 case,输出 “Two” 和 “Three”。

switch 语句的类型分支

switch 语句可以用于类型分支,用于接口值的类型判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
    var i interface{} = 10
    switch v := i.(type) {
    case int:
        fmt.Printf("Integer: %d\n", v)
    case string:
        fmt.Printf("String: %s\n", v)
    default:
        fmt.Printf("Other type: %T\n", v)
    }
}

解释:i 是一个 interface{} 类型,switch 语句根据 i 的实际类型进行匹配,输出 “Integer: 10”。

这些示例展示了 Go 语言中 switch 语句的多种用法,使得条件判断更加简洁和灵活。

select

在 Go 语言中,select 语句用于处理多个 channel 的操作。select 语句会阻塞,直到其中的某个 case 可以继续执行,然后执行这个 case 的代码。以下是一些使用 select 语句的例子,展示了如何在不同情况下使用它。

基本使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
  "fmt"
  "time"
)

func main() {
  // 创建两个 channel
  ch1 := make(chan string)
  ch2 := make(chan string)

  // 启动两个 goroutine,向 channel 发送消息
  go func() {
    time.Sleep(1 * time.Second)
    ch1 <- "Message from ch1"
  }()

  go func() {
    time.Sleep(2 * time.Second)
    ch2 <- "Message from ch2"
  }()

  // 使用 select 语句来等待消息
  select {
  case msg1 := <-ch1:
    fmt.Println(msg1)
  case msg2 := <-ch2:
    fmt.Println(msg2)
  }
}

在这个例子中,select 语句会阻塞,直到 ch1ch2 中有消息到达。由于 ch1 的消息先到达,所以输出将会是 “Message from ch1”。

带超时的 select 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
  "fmt"
  "time"
)

func main() {
  ch := make(chan string)

  go func() {
    time.Sleep(3 * time.Second)
    ch <- "Message"
  }()

  select {
  case msg := <-ch:
    fmt.Println(msg)
  case <-time.After(2 * time.Second):
    fmt.Println("Timeout")
  }
}

在这个例子中,select 语句包含一个超时 case。如果在 2 秒内没有收到消息,则会执行超时 case,输出 “Timeout”。

循环中的 select 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
  "fmt"
  "time"
)

func main() {
  ch1 := make(chan string)
  ch2 := make(chan string)

  go func() {
    for {
      time.Sleep(1 * time.Second)
      ch1 <- "Message from ch1"
    }
  }()

  go func() {
    for {
      time.Sleep(2 * time.Second)
      ch2 <- "Message from ch2"
    }
  }()

  for {
    select {
    case msg1 := <-ch1:
      fmt.Println(msg1)
    case msg2 := <-ch2:
      fmt.Println(msg2)
    case <-time.After(3 * time.Second):
      fmt.Println("Timeout")
      return
    }
  }
}

这个例子展示了如何在循环中使用 select 语句。程序会持续从 ch1ch2 接收消息并输出。如果 3 秒内没有消息到达,则输出 “Timeout” 并退出循环。

带默认 case 的 select 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
  "fmt"
)

func main() {
  ch := make(chan string)

  select {
  case msg := <-ch:
    fmt.Println("Received:", msg)
  default:
    fmt.Println("No message received")
  }
}
  • 在这个例子中,select 语句带有一个 default case。如果 ch 没有消息,则会执行 default case,输出 “No message received”。
  • 通过这些示例,可以看出 select 语句在处理并发编程中的强大功能,能够简洁地处理多个 channel 的操作,并且可以通过超时和默认 case 来增强程序的健壮性。
This post is licensed under CC BY 4.0 by the author.