當接收方從通道接收到一個值類型的值時,對該值的修改就不會影響到發送方持有的那個原值。但對於引用類型的值來說,這種修改會同時影響手法雙方持有的值。
// 86_chan傳引用類型
package main
import (
"fmt"
"time"
)
var mapChan = make(chan map[string]int, 1)
func main() {
synChan := make(chan struct{}, 2)
go func() { // 用於演示接收操作
for {
if elem, ok := <-mapChan; ok {
elem["count"]++
} else {
break
}
}
fmt.Println("Stopped. [receiver]")
synChan <- struct{}{}
}()
go func() { // 用於演示發送操作
countMap := make(map[string]int)
for i := 0; i < 5; i++ {
mapChan <- countMap
time.Sleep(time.Millisecond)
fmt.Printf("The count map: %v. [sender]\n", countMap)
}
close(mapChan)
synChan <- struct{}{}
}()
<-synChan
<-synChan
fmt.Println("#####END####")
}
運行結果:
The count map: map[count:1]. [sender]
The count map: map[count:2]. [sender]
The count map: map[count:3]. [sender]
The count map: map[count:4]. [sender]
The count map: map[count:5]. [sender]
Stopped. [receiver]
#####END####
如上述代碼所示,mapChan的元素類型屬於引用類型。因此,接收方對元素值的副本修改會影響到發送方持有的源值。
不過有時候被傳遞的值的類型不能簡單的判定爲值類型或引用類型。例如,一個結構體類型的值中包含了類型爲切片的字段,在這種情況下,就要特別注意,要仔細檢查對他們的修改的影響,以及這種影響是否符合預期。看下面程序:
// 87_chan值傳遞和引用傳遞
package main
import (
"fmt"
"time"
)
//Count代表計數器的類型
type Counter struct {
count int
}
//var mapChan = make(chan map[string]Counter, 1)
var mapChan = make(chan map[string]Counter, 1)
func main() {
synChan := make(chan struct{}, 2)
go func() { // 用於演示接收操作
for {
if elem, ok := <-mapChan; ok {
counter := elem["count"]
counter.count++
} else {
break
}
}
fmt.Println("Stopped. [receiver]")
synChan <- struct{}{}
}()
go func() { // 用於演示發送操作
countMap := map[string]Counter{
"count": Counter{},
}
//countMap := map[string]*Counter{
// "count": &Counter{},
//}
for i := 0; i < 5; i++ {
mapChan <- countMap
time.Sleep(time.Millisecond)
fmt.Printf("The count map: . [sender]\n", countMap["count"])
}
close(mapChan) //無論怎樣都不應該在接收端關閉通道
synChan <- struct{}{}
}()
<-synChan
<-synChan
fmt.Println("########END#######")
}
運行結果:
The count map: . [sender]
%!(EXTRA main.Counter={0})The count map: . [sender]
%!(EXTRA main.Counter={0})The count map: . [sender]
%!(EXTRA main.Counter={0})The count map: . [sender]
%!(EXTRA main.Counter={0})The count map: . [sender]
%!(EXTRA main.Counter={0})Stopped. [receiver]
########END#######
Process finished with exit code 0
但要是稍微修改下程序,
// 87_chan值傳遞和引用傳遞
package main
import (
"fmt"
"time"
)
//Count代表計數器的類型
type Counter struct {
count int
}
//var mapChan = make(chan map[string]Counter, 1)
var mapChan = make(chan map[string]*Counter, 1)
func main() {
synChan := make(chan struct{}, 2)
go func() { // 用於演示接收操作
for {
if elem, ok := <-mapChan; ok {
counter := elem["count"]
counter.count++
} else {
break
}
}
fmt.Println("Stopped. [receiver]")
synChan <- struct{}{}
}()
go func() { // 用於演示發送操作
//countMap := map[string]Counter{
// "count": Counter{},
//}
countMap := map[string]*Counter{
"count": &Counter{},
}
for i := 0; i < 5; i++ {
mapChan <- countMap
time.Sleep(time.Millisecond)
fmt.Printf("The count map: . [sender]\n", countMap["count"])
}
close(mapChan) //無論怎樣都不應該在接收端關閉通道
synChan <- struct{}{}
}()
<-synChan
<-synChan
fmt.Println("########END#######")
}
運行結果會不一樣,自己運行下看看,注意遇上一個程序的區別:*和&