Day03(运算符与条件语句)
运算符
在 Go 语言(又称 Golang)中,并没有直接列出所有可能的运算法种类,因为运算法(或称为运算符)是编程语言的内置特性,用于执行不同类型的计算或逻辑操作。但是,我们可以分类列出 Go 语言中常用的运算法种类:
-
算术运算符:
- 加法 (
+
) - 减法 (
-
) - 乘法 (
*
) - 除法 (
/
) - 整除(取整)(
%
或%%
,在某些情况下) - 自增 (
++
) - 自减 (
--
)
- 加法 (
-
关系运算符(或比较运算符):
- 等于 (
==
) - 不等于 (
!=
) - 大于 (
>
) - 小于 (
<
) - 大于等于 (
>=
) - 小于等于 (
<=
)
- 等于 (
-
逻辑运算符:
- 逻辑与 (
&&
) - 逻辑或 (
||
) - 逻辑非 (
!
)
- 逻辑与 (
-
位运算符:
- 位与 (
&
) - 位或 (
|
) - 位异或 (
^
) - 位与非 (
&^
) - 左移 (
<<
) - 右移 (
>>
) - 无符号右移 (
>>>
,但 Go 中没有无符号右移运算符)
- 位与 (
-
赋值运算符:
- 赋值 (
=
) - 复合赋值(例如
+=
、-=
、*=
、/=
等)
- 赋值 (
-
其他运算符:
- 地址运算符 (
&
用于获取变量的地址,但在赋值上下文中作为位与运算符) - 指针解引用 (
*
用于解引用指针) - 长度和容量运算符 (
len()
和cap()
,它们不是真正的运算符,但常用于数组、切片、映射和通道) - 索引和切片 (
[]
,用于数组、切片和字符串的索引或切片操作) - 通道运算符 (
<-
,用于发送和接收通道的数据)
- 地址运算符 (
-
类型断言和类型转换:
- 类型断言 (
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 / 3
或float64(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 |
- 例子 以下是逻辑运算符的表格形式,以及每个运算符的示例:
运算符 | 描述 | 示例(假设 a 为 true ,b 为 false ) |
||
---|---|---|---|---|
&& |
逻辑与(AND) | 如果 a && b ,则结果为 false (因为 b 为 false ) |
||
` | ` | 逻辑或(OR) | 如果 a | | b ,则结果为 true (因为 a 为true ) |
|
! |
逻辑非(NOT) | 如果 !a ,则结果为 false (因为 a 为 true ,取反后为 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
}
在这个示例中,我们定义了两个布尔变量 a
和 b
,分别赋值为 true
和 false
。然后,我们使用逻辑运算符 &&
、||
和 !
对这两个变量进行运算,并将结果打印出来。逻辑与 &&
的结果只有在两个操作数都为 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
语句,以及与之相关的else
和else 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
语句会阻塞,直到 ch1
或 ch2
中有消息到达。由于 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
语句。程序会持续从ch1
和ch2
接收消息并输出。如果 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 来增强程序的健壮性。