一篇文章帶你瞭解 Go 語言基礎之指針
前言
Hey,大家好呀,我是星期八
作爲 21 世紀的 C 語言,Go 可能多方面思考,最終還是保留了指針。
但是要比 C 語言指針簡單很多,一起來看看叭。
引言
因爲 Go 語言是類 C 語言,所以爲了提高效率,仍然保留了指針。
但是如果沒有接觸過指針,可能學起來指針需要多多思考一下了。
指針通常情況下,也被稱爲小白勸退神奇。
基本類型指針的理解
先看這兩行代碼。
var n1 int = 666
fmt.Println(n1)//結果:666
fmt.Printf("%p\n",n1)//結果:%!p(int=666),說明不是一個地址,就是一個值
內存分佈圖如下。
再看看這樣兩行代碼,這裏用到了&
。
var n1 int = 1
//表示取n1的地址
fmt.Println(&n1)//結果:0xc00000a0b8
fmt.Printf("%p\n",&n1)//結果:0xc00000a0b8
如圖所示。
如果這兩個能理解,恭喜你,指針已經會了一半了。
引用類型指針的理解
先看這樣的代碼。
var studentList = []string{"張三", "李四"}//一個切片
fmt.Println(studentList) //結果:[張三 李四]
fmt.Printf("%p\n", studentList) //結果:0xc0000044a0
//去地址
fmt.Printf("%p\n", &studentList) //結果:0xc0000044a0
內存分佈圖如下。
值類型和引用類型
值類型
在 Go 中,值類型主要有。
int
,float
,bool
,string
,數組
,struct(結構體)
內存分佈大致如下。
注: 像字符串
,數組
,結構體
這些屬於連續存儲,變量指向的是它們的第一個地址,剩下的會根據長度計算。
引用類型
在 Go 中,引用類型主要有。
切片(slice)
,map
,管道(chan)
內存分佈大致如下。
棧內存和堆內存的區別
棧內存在存儲上,只能存一些簡單的東西,比如數字了,字符了,浮點數了之類的,但是棧內存分配的內存程序員不用回收,由系統自己回收,並且性能很高。
堆內存在存儲上就比較豐富了,隨便存,像 map,隨便塞,但是堆內存分配的內存需要程序員自己回收,典型例子,C++
,如果語言由GC
由GC
回收,性能稍弱那麼一點點點....,但是人家能隨便存啊,多隨便。
&
和*
的意思
&
叫做取地址符。
*
叫做收地址符吧。
示例
var c *int//*int是一個整體,說明c這個變量只能接收int類型的
*int
是一個整體,表示 c 這個變量只能接收**int
類型**的**地址**。
代碼
package main
import "fmt"
func main() {
var c *int
var d int = 1
//c = d//錯誤需要的是d的地址
c = &d
fmt.Println(c)
}
執行結果。
可以看到打印的也是一個地址,但是內存圖還是基本類型圖。
如果要打印c
的值,直接*c
就好了,取得就是地址裏面對應得值了。
fmt.Println(*c)
關於函數
我們一直在強調,操作只會操作棧上面的值,函數同理。
package main
import "fmt"
func say1(x int) {
//x int 相當於隱藏了一行代碼
//隱藏的代碼時 var x int = x,一定要記住這個
fmt.Printf("say1:%p\n", x)
}
func say2(x *int) {
//隱藏的代碼是 var x *int = x,x是一個地址
fmt.Printf("say2:%p\n", x)
}
func say3(x []int) {
//隱藏的代碼是 var x []int = x,因爲x是引用類型,所以x是一個地址
fmt.Printf("say3:%p\n", x)
}
func main() {
say1(1)//棧上面是1,所以傳進去就是1
var x1 = 1
say2(&x1)//say只能接收整數地址
var x2 = []int{1, 1}
say3(x2)//x2是引用類型,所以傳進去的時候就是地址,棧上面的就是地址
}
執行結果。
總結
上述我們主要講述了基本類型指針和引用類型指針,也叫做值類型和引用類型,並且畫出了值類型和引用類型內存的本質區分圖,後來又講了&
和*
的區別,還有函數傳參的本質是什麼,希望對大家的學習有幫助。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/D06s52k2AvyyjDfvqE43GQ