本篇内容:
① errors.Is方法与==方式进行error比较
② 带缓冲channel和无缓冲channel区别
正文:
errors.Is
方法与==
两种方式进行error
比较
在Go语言中,处理错误(error 类型)时,errors.Is 和直接使用 == 操作符进行错误比较,虽然看起来都用于比较错误,但实际上它们有着根本的不同。这主要体现在对错误值的比较方式和用途上。
1) 使用 == 操作符
直接使用 == 操作符来比较两个错误值,实际上是比较这两个错误变量的内存地址是否相同。这意味着,除非这两个错误变量引用的是同一个错误实例(即指向相同的内存地址),否则 == 将返回 false。这种比较方式对于区分不同的错误实例(即使它们包含相同的错误信息)非常严格,并且不常用于错误处理,因为它通常不是你所需要的比较方式。
2) 使用 errors.Is
errors.Is 函数用于判断一个错误是否是由特定的错误或错误的类型产生的。这意呀着,即使两个错误值不是同一个实例(即它们的内存地址不同),只要它们在类型上或者通过错误包装(wrapping)关系上是相关的,errors.Is 也能返回 true。
errors.Is 函数特别适合与错误包装(%w 格式化指令在 fmt.Errorf 中)一起使用,用于判断一个错误是否是由于某个特定的底层错误引起的。
代码示例 :
代码语言:go复制var myErr = errors.New("my err")
func TestError(t *testing.T) {
err := fmt.Errorf("hello %w", myErr)
fmt.Printf("myErr:%s , err:%s n", myErr, err)
fmt.Println("使用 == 的结果:", err == myErr)
fmt.Println("使用 errors.Is(err, myErr) 的结果:", errors.Is(err, myErr))
fmt.Println("使用 errors.Is(myErr, err) 的结果:", errors.Is(myErr, err))
}
输出:
代码语言:shell复制myErr:my err , err:hello my err
使用 == 的结果: false
使用 errors.Is(err, myErr) 的结果: true
使用 errors.Is(myErr, err) 的结果: false
带缓冲channel和无缓冲channel区别
Go语言中的channel是用于在不同的goroutine之间进行通信的一种机制。channel可以是带缓冲的,也可以是无缓冲的,它们之间有一些关键的区别:
无缓冲channel:
无缓冲的channel没有存储空间,发送操作会阻塞直到另一方准备好接收数据,接收操作也会阻塞直到有数据可以接收。
代码示例:
代码语言:go复制func TestNoBufferChannel(t *testing.T) {
ch := make(chan int)
go func() {
ch <- 10
fmt.Println("Send data to channel")
}()
time.Sleep(time.Second * 3) // 确保goroutine有足够的时间执行
data := <-ch
fmt.Println("Received data:", data)
}
输出:
代码语言:go复制Received data: 10
Send data to channel
带缓冲channel:
Go语言中的channel是一种用于在不同的goroutine之间进行通信的机制。Channel可以是带缓冲的(buffered)或不带缓冲的(unbuffered),它们之间的主要区别在于数据的发送和接收方式。
带缓冲的channel有固定的存储空间,可以在channel满之前存储数据项。发送操作只会在缓冲区满时阻塞,接收操作会在缓冲区为空时阻塞。可以使用len函数查看当前缓冲区中剩余元素的数量,使用cap函数查看缓冲区的容量。
代码示例:
代码语言:go复制func TestHasBufferChannel(t *testing.T) {
ch := make(chan int, 2) // 创建一个容量为2的带缓冲channel
ch <- 10
ch <- 20
go func() {
time.Sleep(time.Second * 2)
ch <- 30 // 这条语句会阻塞,直到缓冲区有空间
}()
data := <-ch
fmt.Println("Received data:", data)
data = <-ch
fmt.Println("Received data:", data)
time.Sleep(time.Second * 3) // 等待足够的时间来接收最后一条数据
data = <-ch
fmt.Println("Received data:", data)
}
输出:
代码语言:shell复制Received data: 10
Received data: 20
Received data: 30
在无缓冲channel的例子中,主goroutine和发送goroutine之间的操作是同步的。而在带缓冲channel的例子中,发送goroutine可以继续发送数据,直到缓冲区满为止,而接收goroutine可以从缓冲区接收数据,而不需要等待发送操作
本篇结束~