作为一个多年C++学习者,记录一下学go的过程中遇到的很多go语言独特的难以记忆的内容
GO中常用的格式化占位符
- 字符串:
%s,表示字符串。 - 整数:
%d(十进制),%x(十六进制),%o(八进制),%b(二进制)。 - 浮点数:
%f(小数形式),%e(科学计数法),%g(最简表示法)。 - 控制浮点数的精度:可以通过
%.[数字]f来控制小数点后的位数。 - 布尔值:
%t,表示布尔值(true或false)。 - 通用格式:
%v,无需知道变量的类型,直接打印变量的值;%+v,打印结构体时显示字段名;%#v,显示变量的 Go 语法表示。 - 类型:
%T,直接打印出变量的类型
引用类型
在 Go 中,引用类型是指可以存储和引用数据位置(内存地址)的类型。这些类型允许多个变量共享同一块数据,因为它们都指向同一个内存地址,而不是独立存储数据的副本。Go 中的引用类型包括以下几种:
- 指针(Pointer)
- 切片(Slice)
arr := [5]int{1,2,3,4,5}
slice := arr[1:4]
// sclice是arr的切片,它引用了arr当中的一部分元素,修改slice也会修改arr
- 映射(Map)
- 通道(Channel)
func greet(roc <-chan string) {
fmt.Println("Hello " + <-roc ,"!")
}
func main() {
fmt.Println("Main Start")
c := make(chan string)
go greet(c)
c <- "Demo"
fmt.Println("Main Stop")
}
- 接口(Interface)
select语句
select 关键字的语法和作用都和其他语言当中的switch语句非常类似,但是它主要用于处理多个通道操作的情况。它允许 goroutine 等待多个通道中的任何一个操作(发送或接收),并在其中一个通道准备好的时候执行相应的操作。select 吞噬了在处理多个通道时的复杂性,是实现并发程序的一个重要工具
select {
case expr1:
// channel1 准备好,处理 expr1
case expr2:
// channel2 准备好,处理 expr2
case expr3:
// channel3 准备好,处理 expr3
default:
// 如果没有通道准备好,执行这个语句
}
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
case msg3 := <-ch3:
fmt.Println(msg3)
default:
fmt.Println("没有通道准备好")
}
}
select会轮询每一个case分支,检查通道是否准备好- 如果有通道已经准备好(即有数据可接收),就会执行相应的
case分支,并接收数据 - 如果所有通道都未准备好,则执行
default分支,输出"没有通道准备好" - 循环进行了两次,这意味着将会接收两个通道的数据(因为
i < 2的限制)。
单次的select只会进行一次的选择,只有将select语句配合for循环去使用,才能够保证持续的去监听通道,如果所有的 case 语句(通道操作)被阻塞,那么 select 语句将阻塞直到这些 case 条件的一个不阻塞(通道操作),case 块执行。如果有多个 case 块(通道操作)都没有阻塞,那么运行时将随机选择一个不阻塞的 case 块立即执行
nil值
在 Go 中,nil 是一种特殊的零值,表示一个“空”或“未初始化”的状态。它可以用于多种类型的值,包括指针、切片、映射、通道和接口。每种类型的 nil 都有独特的行为,尤其是在通道中,nil 通道有一些重要特性和注意事项
nil 是一个预定义标识符,用于表示指针、通道、映射、切片和接口等引用类型的零值。通常用来表示一个变量没有被初始化或指向空的内存地址,我的理解就是相当于把C++当中的0,NULL, nullptr的特殊的零值做了一个统一,简化了程序员的操作。
var p *int // p 是一个 nil 指针
var s []int // s 是一个 nil 切片
var m map[string]int // m 是一个 nil 映射
var ch chan int // ch 是一个 nil 通道
nil通道的行为
与已初始化的通道不同,nil 通道的特性非常独特,任何操作都会被永久阻塞。它的行为如下:
- 发送:对
nil通道进行发送操作会阻塞,程序不会继续执行。 - 接收:对
nil通道进行接收操作也会阻塞,程序不会继续执行。 - 关闭:对
nil通道进行关闭操作会导致运行时异常(panic)。
示例:
var ch chan int // ch 是 nil 通道
// 发送操作会阻塞
go func() {
ch <- 1 // 会阻塞在这里,永远不会发送成功
}()
// 接收操作会阻塞
go func() {
<-ch // 会阻塞在这里,永远不会接收到数据
}()
nil通道可以灵活的用于控制select分支的执行