Go起步:5、複合類型2--指針(pointer)、結構體(struct)

之前關於Go的複合類型聊到數組和切片,今天繼續看看指針(pointer)和結構體(struct)。

指針(pointer)

取地址符–&

Go具有指針。指針保存了變量的內存地址。
我們都知道,變量是一種使用方便的佔位符,用於引用計算機內存地址。
這裏先要說下Go語言的取地址符– &,放到一個變量前使用就會返回相應變量的內存地址。

package main

import "fmt"

func main() {
    var a int = 20
    var s string = "a"

    fmt.Printf("a 變量的存儲地址: %x\n", &a)
    fmt.Printf("s 變量的存儲地址: %x\n", &s)
}

%x是十六進制輸出。
這裏寫圖片描述
這裏寫圖片描述

可以看出,兩次運行的結果中,int型的變量地址不同的,string型的變量地址是相同的,這點是不是和java一樣呢?–int是值類型,string是引用類型。

指針的定義

類型 *T 是指向 T 類型值的指針。其零值爲 nil 。

var p *int

以上定義了一個int類型的指針。
& 操作符會生成一個指向其操作數的指針。
* 操作符表示指針指向的底層值。

package main

import "fmt"

func main() {
    var p *int //定義一個指針變量
    fmt.Printf("p 變量的初始存儲地址: %x\n", p)

    i := 10
    p = &i //將指針指向變量i

    fmt.Printf("p 變量的存儲地址: %x\n", p)
    /* 使用指針訪問值 */
    fmt.Printf("*p 變量的值: %d\n", *p)
    fmt.Printf("i 變量的值: %d\n", i)
    *p = 20 //通過指針 p 設置 i
    fmt.Printf("p 變量的存儲地址: %x\n", p)
    /* 使用指針訪問值 */
    fmt.Printf("*p 變量的值: %d\n", *p)
    fmt.Printf("i 變量的值: %d\n", i)
}

這裏寫圖片描述
可以看出,

  • 指正定義是默認的地址是0,這時它的值就是nil。
  • 當指針指向變量i時,它的地址就變成了變量i的地址,通過&操作符完成,這時他的值就是變量i的值。
  • 當通過操作符*改變指針的值時,對應的i的值也發生了變化,以爲他們引用的是同一個地址上的值。
    這也就是通常所說的“間接引用”或“重定向”。
    總結一下,使用指針需要三步,首先,定義指針變量。然後,爲指針變量賦值(&)。最後就可以訪問指針變量中指向地址的值(*)。

指針的指針

如果一個指針變量存放的又是另一個指針變量的地址,則稱這個指針變量爲指向指針的指針變量。當定義一個指向指針的指針變量時,第一個指針存放第二個指針的地址,第二個指針存放變量的地址。
這裏寫圖片描述
聲明格式如下:

var ptr **int;

以上指向指針的指針變量爲整型。

package main

import "fmt"

func main() {

    var a int
    var ptr *int
    var pptr **int

    a = 10

    /* 指針 ptr 地址 */
    ptr = &a

    /* 指向指針 ptr 地址 */
    pptr = &ptr

    /* 獲取 pptr 的值 */
    fmt.Printf("變量 a = %d\n", a)
    fmt.Printf("變量 a 內存地址 %x\n", &a)
    fmt.Printf("指針變量 *ptr = %d\n", *ptr)
    fmt.Printf("指針變量 *ptr 內存地址 %x\n", &*ptr)
    fmt.Printf("指向指針的指針變量 **pptr = %d\n", **pptr)
    fmt.Printf("指向指針的指針變量 **pptr 內存地址 %x\n", &**pptr)
}

這裏寫圖片描述
可以看出,變量a,ptr,pptr都指向了同一個地址。實際上他們引用的是同一個內存地址,所以他們的值也都是一樣的。
總之,指針在Go中的用途還是很廣泛的,大部分同C語言的也有些共通指出,但與 C 不同,Go 沒有指針運算。

結構體(struct)

結構體( struct )就是由一系列具有相同類型或不同類型的數據構成的字段集合。在結構體中可以爲不同項定義不同的數據類型。

定義和初始化

struct關鍵之用於定義結構體,type 聲明就是定義的類型。

type T struct {
    name string // name of the object
    value int // its value
}

如下的代碼:

package main

import "fmt"

type Vertex struct {
    X int
    Y string
}

func main() {
    var v = Vertex{1, "s"}
    fmt.Println(v)
    fmt.Println(v.X)
    fmt.Println(v.Y)
    v.X = 10
    fmt.Println(v.X)
}

這裏寫圖片描述
上面的代碼定義了一個名爲Vertex的結構體,結構體是由int和string兩個數據類型構成。
然後在main函數中定義了一個類型爲Vertex的變量。通過上面的程序也可以得出,操作一個結構體的內容直接通過.操作符就可以了,不管是取值還是賦值。

結構體指針

結構體指針就是指向結構體的指針,類似於其他指針變量。定義結構體指針,結構體的字段就可以通過結構體指針來訪問。
特殊的前綴 & 返回一個指向結構體的指針。
如果我們有一個指向結構體的指針 p ,那麼可以通過 (*p).X 來訪問其字段 X 。 不過這麼寫太囉嗦了,所以語言也允許我們使用隱式間接引用,直接寫 p.X 就可以。

package main

import "fmt"

type Vertex struct {
    X int
    Y string
}

func main() {
    v := Vertex{1, "2"}
    p := &v
    p.X = 333333333
    fmt.Println(v)
    fmt.Println(p.X)
    fmt.Println((*p).X)
}

這裏寫圖片描述
可以看出,定義的指向結構體v的指針p,對於p的修改就是修改了之前的結構體v。

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