
本文旨在阐明Go语言中打印`sync.WaitGroup`指针地址时常见的混淆点,特别是当一个函数返回`*sync.WaitGroup`类型时。我们将通过代码示例详细解析`&wg`和`wg`在不同作用域中的含义,帮助开发者区分变量本身的地址与变量所存储的指针值,从而避免因误解而产生的地址不一致现象。
在Go语言中,理解变量、指针以及它们在不同作用域中的行为至关重要,尤其是在处理并发原语如sync.WaitGroup时。开发者有时会发现,当一个函数返回*sync.WaitGroup后,在调用方打印该指针的地址与在函数内部打印的地址不一致,这通常是由于对Go语言中&操作符和变量本身含义的混淆所致。
考虑以下Go语言代码片段,它尝试使用sync.WaitGroup来协调主协程与一个子协程的执行,并打印WaitGroup的内存地址:
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func Run() *sync.WaitGroup {
var wg sync.WaitGroup // 声明一个 WaitGroup 实例
wg.Add(1)
go func() {
defer wg.Done()
fmt.Printf("goroutine %p\n", &wg) // 打印 wg 实例的地址
time.Sleep(5 * time.Second)
fmt.Println("wokeup")
}()
fmt.Printf("returning %p\n", &wg) // 打印 wg 实例的地址
return &wg // 返回 wg 实例的地址
}
func main() {
runtime.GOMAXPROCS(3)
wg := Run() // 接收 Run 函数返回的 *sync.WaitGroup
fmt.Printf(" main %p\n", &wg) // 打印 wg 变量的地址
wg.Wait()
}运行上述代码,可能会得到类似以下的输出:
立即学习“go语言免费学习笔记(深入)”;
returning 0xc00000e000
main 0xc000006020
goroutine 0xc00000e000
wokeup从输出中可以看到,Run函数内部和goroutine中打印的地址(0xc00000e000)是一致的,但main函数中打印的地址(0xc000006020)却不同。这似乎与预期不符,因为我们期望在main函数中得到的WaitGroup指针地址应该与Run函数中返回的地址相同。
问题的核心在于对&操作符的理解以及变量在不同作用域中的表示。
在Run函数内部 (Run和goroutine):
在main函数内部:
简单来说,Run函数返回的是一个门牌号(WaitGroup实例的地址),而main函数中的wg变量是一个信箱,里面存放着这个门牌号。&wg在main函数中打印的是信箱本身的地址,而不是信箱里存放的门牌号。
要使main函数中打印的地址与Run函数中返回的WaitGroup实例地址一致,我们应该打印main函数中wg变量所存储的值,而不是wg变量本身的地址。由于wg在main函数中已经是一个*sync.WaitGroup类型的指针,其值就是WaitGroup实例的地址。
因此,只需将main函数中的打印语句从fmt.Printf(" main %p\n", &wg)修改为fmt.Printf(" main %p\n", wg)。
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func Run() *sync.WaitGroup {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
fmt.Printf("goroutine %p\n", &wg) // 打印 wg 实例的地址
fmt.Println("sleep for 5s")
time.Sleep(5 * time.Second)
fmt.Println("wokeup")
}()
fmt.Printf("returning %p\n", &wg) // 打印 wg 实例的地址
return &wg // 返回 wg 实例的地址
}
func main() {
runtime.GOMAXPROCS(3)
wg := Run()
fmt.Printf(" main %p\n", wg) // **修正点:打印 wg 变量存储的指针值**
wg.Wait()
}修正后的代码运行输出如下:
returning 0x1052e2c0
main 0x1052e2c0
goroutine 0x1052e2c0
sleep for 5s现在,所有打印的地址都一致了,它们都指向了同一个sync.WaitGroup实例的内存地址。
通过区分变量本身的地址和变量所存储的指针值,我们可以准确地追踪Go程序中对象的内存位置,从而避免常见的混淆和错误。
以上就是深入理解Go语言中sync.WaitGroup指针地址的打印行为的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号