当接收方从通道接收到一个值类型的值时,对该值的修改就不会影响到发送方持有的那个原值。但对于引用类型的值来说,这种修改会同时影响手法双方持有的值。
// 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#######")
}
运行结果会不一样,自己运行下看看,注意遇上一个程序的区别:*和&