GO語言學習——(3) channel之影響發送方的原值

   當接收方從通道接收到一個值類型的值時,對該值的修改就不會影響到發送方持有的那個原值。但對於引用類型的值來說,這種修改會同時影響手法雙方持有的值。

// 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#######")
}

運行結果會不一樣,自己運行下看看,注意遇上一個程序的區別:*和&

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章