Golang:在延迟函数中可以关闭通道吗?

huangapple go评论68阅读模式
英文:

Golang: Can channels be closed in a deferred function?

问题

我正在处理一些Go代码,并希望在代码结束时关闭一个通道。然而,我想测试一下,如果我使用一个匿名函数,将通道作为参数传递,并在defer关键字中使用该函数,它是否会真正关闭通道。

根据我的理解,在Go中,所有东西都是按值传递而不是按引用传递,而且make函数的文档说,当用于创建通道时,它返回的是一个通道,而不是一个通道的指针。这是否意味着,如果我将通道作为参数传递给一个函数,并在该函数内部关闭通道,函数外部的通道将保持打开状态?如果是这样,我猜想我需要将通道作为指针传递给函数才能实现这种行为?

我对Go还不太熟悉,所以如果你能解释一下为什么而不是告诉我“哦,只需将这一部分代码替换为另一部分代码”,这样我就能更好地理解它是如何工作的:)

谢谢!

英文:

I was working on some Go code and wanted to close a channel at the end of it. However, I wanted to test if it'd actually close the channel if I use an anonymous function, passing the channel as an argument and use the function with the defer keyword.

channel := make(chan string, 2) 

defer func (channel chan string) {
		close(channel)
		value, ok := <-channel
		fmt.Println("Value:", value, "Open channel?", ok)
	}(channel)

To my understanding everything in Go is passed by value and not by reference, and make's documentation says that it returns a channel when used to spawn a channel, not a pointer to a channel. Does this imply that if I pass the channel as argument to a function and close the channel within that function, the channel outside the function would remain open? If so, I'm guessing I'd need to pass the channel as a pointer to the function to achieve that behavior?

I'm new to Go, so I'd appreciate if you can explain me the "why" rather than "Oh, just swap this chunk for this other chunk of code" just so I can better understand how it's actually working:)

Thanks!

答案1

得分: 3

通道(Channels)的行为类似于切片(slice)、映射(map)、字符串(strings)或函数(functions),它们实际上存储了对底层数据的包装指针。它们的行为类似于不透明指针。

因此,传递通道是通过值进行复制的,但就像切片一样,它的“值”实际上只是对实际底层通道数据结构的引用。因此,没有必要显式传递通道指针,因为那就像传递指针的指针一样。

回答你的问题:是的,可以传递通道,并且通过值传递通道是安全的,因为它们本身就是“指针”。

你还可以通过稍微修改你的代码来验证这一点:

package main

import "fmt"

func main() {
	channel := make(chan string, 2)

    // 通道在这里是打开的。

    // 通过将通道按值传递给函数并在函数内部关闭它来关闭通道。
	func(channel chan string) {
		close(channel)
	}(channel)

    // 通道是否关闭?
	value, ok := <-channel
	fmt.Println("Value:", value, "通道是否打开?", ok)
}

输出(go version go1.16 darwin/amd64):

Value:  Open channel? false
英文:

Channels behaves like slice, map, strings or functions, as in they actually store a wrapped pointer to the underlying data. They behave like opaque pointers.

So passing a channel is copying it by value, but just like a slice, it's "value" is literally just a reference to the actual low-level channel data structure. So there is no need to explicitly pass a channel pointer, since that would be like passing a pointer of a pointer.

To answer your questions: Yes it can and yes it's safe to pass channels by value because they are "pointers" in and of themselves.


You can also verify it with a slightly modified version of your code:

package main

import &quot;fmt&quot;

func main() {
	channel := make(chan string, 2)

    // channel is open here.

    // close the channel by passing it into a function
    // by value and closing it within the function.
	func(channel chan string) {
		close(channel)
	}(channel)

    // is the channel closed?
	value, ok := &lt;-channel
	fmt.Println(&quot;Value:&quot;, value, &quot;Open channel?&quot;, ok)
}

Output (go version go1.16 darwin/amd64):
<pre>
Value: Open channel? false
</pre>

答案2

得分: 0

这是否意味着,如果我将通道作为参数传递给一个函数,并在该函数内关闭通道,那么函数外部的通道将保持打开状态?

不会。复制 chan 变量并不会产生通道本身的副本。chan 类型的变量是对由 make 创建的底层通道的句柄。关闭任何 chan 变量的副本都会关闭通道。

英文:

> Does this imply that if I pass the channel as argument to a function and close the channel within that function, the channel outside the function would remain open?

No. Copying a chan variable doesn't produce a copy of the channel itself. Variables of type chan are handles to the underlying channel created by make. Closing any copy of the chan variable closes the channel.

huangapple
  • 本文由 发表于 2022年2月13日 10:15:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/71097396.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定