Go語言之理解指針

1. 說一下內存

我們在編程的時候,實際上就是在操作內存,除非是進行IO操作寫磁盤。其餘的不管你是一半的變量還是Hibernate的Entity,都是在內存中閃轉騰挪。

我上學的時候,C語言課程是第一門編程語言課程,其中最難的部分就是指針,而指針就是直接操作內存的,所謂的C語言是最接近底層的語言,其中很重要的原因就是以爲C語言讓程序員可以直接去動內存。

其實在很多年前,人們編程的時候絕對不像想在這麼幸福,總是要直接操作內存的,而更久遠一點的程序員們,要用彙編語言直接寫指令,再久一點的程序員,就要在紙帶上打孔,用01010這種二進制編碼編程了。

我說了這麼多,其實想說的是,現在的很多編程語言比如Java,其實是對程序員隱藏了其內存操作的細節的。

我們都知道Java有堆內存和棧內存,堆內存裏是實際的對象,棧內存中的變量指向了對象,這裏的指向,其實就是指針了。那麼指向的是什麼?有沒有人曾經思考過這個問題,在內存中,如何快速的尋找一個值?

答案自然是地址,只有用地址訪問是最快的。

如上圖所示,如果有一種低級語言,也許是這樣的:

//我設計了一種運算符,[]內表示內存地址
var [1] = 101

這樣就將內存地址1的塊設置成了101。

現在時代進步了,我們發明了變量這個概念,其實就是給內存地址起了名字:

var a = 101

此時變量a就是地址1的別名了,可以這麼理解。

2. 現在談談指針

那麼指針是什麼?指針的值是一個變量的地址,一個指針只是值所保存的位置。

下面寫一段正確的Go代碼,這段代碼來自《The Go Programming Language》:

x := 1
p := &x
//打印1
fmt.Println(*p)
*p = 2
//打印2
fmt.Println(x)

這個時候畫一個內存模型,應該是這樣的:

&是取地址運算符,根據變量x,取到了相應的地址,此時如果打印p,得到的是一段類似這樣的字符串:“0xc000016050”。

接下來利用*p=2這個語句將指針指向的值改成2,畫成圖是這樣的:

看看,利用指針我根本不需要去知道變量叫什麼,只要改指針就可以了。

下面再來一段代碼,來源還是一樣的:

package main

import "fmt"

func incr(p *int) int {
    *p++
    return *p
}

func main() {
    v := 1
    incr(&v)
    fmt.Println(incr(&v))
}

這段代碼比較迷惑的地方在於*p++,程序最終的返回結果是3,注意,這一句只是將指針p所指向的值進行了遞增操作,但是並沒有變更p本身,因此畫出圖來是這樣的:

3. 搞點事情

如指針那張圖,其實p也是內存中的一個地址,那麼一定可以有一個指針指向它,這沒毛病:

v := 1
p := &v
q := &p

此時的q就是一個指向指針的指針了。q得到的是p的地址,*q得到的就是p指向的值了。

指向指針的指針在C語言裏常常會用到,我現在初學Go,也不知道會不會頻繁使用,反正有個印象就好了。

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