= 与 := 的区别
· 阅读需 3 分钟
基础用法
=
赋值操作符
- 仅用于赋值,不声明变量
- 可以在任何代码快中使用
var a int
a = 100
:=
短变量声明
- 声明变量的同时赋值
- 只能在函数内部使用
- 在给多个变量的时候赋值的时候,至少要定义一个新变量
a := 100
a,b := 200,300
使用案例
闭包
func closureDemo(){
for i:=0; i< 3;i++ {
go func(){
fmt.Print(i," ") // 闭包
}()
}
}
这段代码可能会输出 3 3 3
,因为 i
是在闭包外部定义的变量,所有的 goroutine
都共享同一个 i
变量。
func closureDemo(){
for i:=0; i< 3;i++ {
val :=i
go func(){
fmt.Print(val," ")
}()
}
}
使用局部变量可以避免闭包带来的问题。每次循环都会创建一个新的变量。
i
变量定义在堆中,val
变量定义在栈中。
func closureDemo(){
for i:=0; i< 3;i++ {
go func(v int){
fmt.Print(v," ")
}(i)
}
}
通过参数将 i
的值传递给闭包函数,确保每个 goroutine 都有自己的 i
值。
并发下的安全赋值/原子操作
func main() {
var counter *int64 = new(int64)
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func(v *int64) {
*v += 1
wg.Done()
}(counter)
}
wg.Wait()
fmt.Println("Counter:", *counter)
}
输出的值小于 1000
func concurrentAssignment() {
var counter int64
var wg sync.WaitGroup
// 使用原子操作保证并发安全
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
atomic.AddInt64(&counter, 1) // 使用=修改共享变量
wg.Done()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
// 使用通道安全传递值
ch := make(chan int)
go func() {
val := <-ch // 使用:=接收新值
fmt.Println("Received:", val)
}()
ch <- 42 // 使用=发送值
}
使用 atomic.AddInt64
来实现原子操作,确保在并发环境下对 counter
的安全修改。