代碼如下:
package main
import (
"fmt"
"time"
)
type Int struct {
int int
}
func multi(i *Int) {
i.int = i.int*100
}
func main() {
a := []Int {
{1},
{2},
{3},
{4},
}
for _, v := range a{
multi(&v)
go func() {
ticker := time.NewTicker(time.Second)
<- ticker.C
fmt.Println(v)
}()
}
time.Sleep(time.Second*5)
fmt.Println(a)
}
理想輸出結果應該爲:
{100}
{200}
{300}
{400}
{{100} {200} {300} {400}}
實際輸出爲:
{400}
{400}
{400}
{400}
{{1} {2} {3} {4}}
問題一:爲何v值一樣?
答:在每個循環中開啓的新goroutine時有停頓一秒,循環已經結束,所有的goroutine裏面的v值是指向同一個地址的值,即最後一次循環的v值。
問題二:爲何數組值沒有改變?
在回答二問題的時候,我還需要列上一組代碼與結果,如下:
package main
import (
"fmt"
)
type Int struct {
int int
}
func multi(i *Int) {
i.int = i.int*100
}
func main() {
a := []Int {
{1},
{2},
{3},
{4},
}
var b = make([]*Int, len(a))
for i, v := range a{
multi(&v)
b[i] = &v
}
fmt.Println(a)
fmt.Println(b[0],b[1],b[2],b[3])
}
結果:
[{1} {2} {3} {4}]
&{400} &{400} &{400} &{400}
答:在Golang的range方法中,始終使用值拷貝的方式代替被遍歷的元素本身,簡單來說,就是for…range
中那個value
,是一個值拷貝,而不是元素本身。這樣一來,當我們期望用&獲取元素的指針地址時,實際上只是取到了value
這個臨時變量的指針地址,而非list
中真正被遍歷到的某個元素的指針地址。因此上訴結果也就得到了完美的解釋。
可再看下例補充:
package main
import "fmt"
func main() {
a := []int {1,2,3,4}
for i, v := range a{
fmt.Println(&v,&a[i])
}
}
結果:
0xc000016078 0xc000018100
0xc000016078 0xc000018108
0xc000016078 0xc000018110
0xc000016078 0xc000018118
所以,range的坑搞懂了。嘿嘿