《Go小技巧&易错点100例》第二十一篇

2024-08-21 22:28:52 浏览数 (2)

本篇内容

① 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可以从缓冲区接收数据,而不需要等待发送操作

本篇结束~

go

0 人点赞