值類型
值類型包括基本數據類型,int,float,bool,string,以及數組和結構體(struct)。注意:sync.WaitGroup 對象是值類型,不是一個引用類型
值類型變量聲明后,不管是否已經賦值,編譯器為其分配內存,此時該值存儲於棧上。
值類型的默認值:
var a int //int類型默認值為 0 var b string //string類型默認值為 nil空 var c bool //bool類型默認值為false var d [2]int //數組默認值為[0 0] fmt.Println(&a) //默認已經分配內存地址,可以使用&來取內存地址
當使用等號=將一個變量的值賦給另一個變量時,如 j = i ,實際上是在內存中將 i 的值進行了拷貝,可以通過 &i 獲取變量 i 的內存地址。此時如果修改某個變量的值,不會影響另一個。
//變量的賦值 var a =10 //定義變量a b := a //將a的值賦值給b b = 101 //修改b的值,此時不會影響a fmt.Printf("a的值是%v,a的內存地址是%p\n",a,&a) //a的值是10,a的內存地址是0xc42000e228 fmt.Printf("b的值是%v,b的內存地址是%p\n",b,&b) //b的值是101,b的內存地址是0xc42000e250 //數組的賦值 var c =[3]int{1,2,3} //定義一個長度為3的int類型的數組 d := c //將數組c賦值給d d[1] = 100 //修改數組d中索引為1的值為100 fmt.Printf("c的值是%v,c的內存地址是%p\n",c,&c) //c的值是[1 2 3],c的內存地址是0xc42000a180 fmt.Printf("d的值是%v,d的內存地址是%p\n",d,&d) //d的值是[1 100 3],d的內存地址是0xc42000a1a0
畫圖示例:
引用類型
引用類型包括指針,slice切片,map ,chan,interface。
變量直接存放的就是一個內存地址值,這個地址值指向的空間存的才是值。所以修改其中一個,另外一個也會修改(同一個內存地址)。
引用類型必須申請內存才可以使用,make()是給引用類型申請內存空間。
var a = []int{1,2,3,4,5} b := a //此時a,b都指向了內存中的[1 2 3 4 5]的地址 b[1] = 10 //相當於修改同一個內存地址,所以a的值也會改變 c := make([]int,5,5) //切片的初始化 copy(c,a) //將切片acopy到c c[1] = 20 //copy是值類型,所以a不會改變 fmt.Printf("a的值是%v,a的內存地址是%p\n",a,&a) //a的值是[1 10 3 4 5],a的內存地址是0xc42000a180 fmt.Printf("b的值是%v,b的內存地址是%p\n",b,&b) //b的值是[1 10 3 4 5],b的內存地址是0xc42000a1a0 fmt.Printf("c的值是%v,c的內存地址是%p\n",c,&c) //c的值是[1 20 3 4 5],c的內存地址是0xc42000a1c0 d := &a //將a的內存地址賦值給d,取值用*d a[1] = 11 fmt.Printf("d的值是%v,d的內存地址是%p\n",*d,d) //d的值是[1 11 3 4 5],d的內存地址是0xc420084060 fmt.Printf("a的值是%v,a的內存地址是%p\n",a,&a) //a的值是[1 11 3 4 5],a的內存地址是0xc420084060
a,b,c底層數組是一樣的,但是上層切片不同,所以內存地址不一樣。