最本質的區別
值類型:內存中變量存儲的是具體的值 比如: var num int num存放的是具體的int值
但是變量在內存中的地址可以通過 &num 來獲取
引用類型:變量直接存放的就是一個地址值,這個地址值指向的空間存的纔是值。
例如:
var ptr *int =& num
值類型,引用類型都包括哪些
基本的數據類型 int系列,float系列,bool,string, 數組和結構體struct
引用類型包括指針,slice切片,map ,chan ,interface
值類型和引用類型的使用特點
值類型 直接存放值,內存通常在棧中分配
應用類型變量存儲的地址(也就是通過指針訪問類型裏面的數據),通常真正的值在堆上分配。當麼有變量引用這個地址的時候,該值會被gc回收。
實例詳解值類型和引用類型
1.數組array和切片slice的實例:
定義了一個數組a,它是值類型,複製給b是copy,當b發生變化後a並不會發生任何變化,程序的執行結果如下所示:
func main() {
a :=[5]int{1,2,3,4,5}
b := a
b[2] = 8
fmt.Println(a, b) //[1,2,3,4,5] [1,2,8,4,5]
}
切片卻相反
func main() {
a :=[]int{1,2,3,4,5}
b := a
b[2] = 8
fmt.Println(a, b) //[1,2,8,4,5] [1,2,8,4,5]
}
2.來一個更復雜的例子,結構體和map
//Count代表計數器的類型
type Counter struct {
count int
}
func add1(s map[string]int) {
s["count"]++
}
func add2(s map[string]Counter) {
counter := s["count"]
counter.count++
}
func add3(s map[string]*Counter) {
counter := s["count"]
counter.count++
}
func add4(s Counter) {
s.count++
}
func main() {
m1 := make(map[string]int)
add1(m1)
add1(m1)
println(m1["count"])
m2 := map[string]Counter{"count":Counter{20}}
add2(m2)
//temp := m2["count"]
//temp.count++
println(m2["count"].count)
m3 := map[string]*Counter{"count":&Counter{20}}
add3(m3)
println(m3["count"].count)
m4 := Counter{20}
add4(m4)
println(m4.count)
}
結果爲:
2
20
21
20
首先明確結構體是值類型,map是引用類型。
我們按m1,m4,m2,m3的順序來講解。
m1 是一個從string到int,聲明的時候進行了零初始化,也就是一開始默認值爲0。由於m1是一個引用類型,所以傳遞給add1的時候會拷貝其底層數據的指針,然後在然後通過指針直接進行操作。
而m4是一個結構體,是值類型。所以傳遞給add4的時候,是對其內存上的值拷貝,也就是add4中的s所在的內存塊跟m4不一樣了。因此,在add4中的任何操作並不會對m4造成影響。
m2,m3是結構體和map的結合。
m2不會改變,主要是因爲add2中使用:=重新聲明瞭counter,由於是對象是值類型,所以也就類似於第一個實例那樣,只是單純的進行了值拷貝。
m3是的add3中雖然看起來一樣。但實際上counter是一個指針,所以對counter進行操作會導致原來的數值也發生改變。
撩我?
我的公衆號:Kyda