8.Go語言基礎之指針

Go語言中的指針不能進行偏移和運算,是安全指針。
在瞭解GO語言中的指針前,首先須要知道三個概念:指針地址、指針類型和指針取值。

1.Go語言中的指針

任何數據載入內存後,在內存中都有對應的地址,這就是指針。
爲了保存一個數據在內存中的地址,須要指針變量。
好比"好好學習,每天向上"這個字符串寫入程序中,程序一啓動這句話就加載到內存(假設內存地址爲0x123456),在程序中,把該字符串賦值給變量A,把該字符串的內存地址賦值給變量B。
這時變量B就是一個指針變量。經過變量A和變量B都能找到該字符串。
Go語言中的指針不能進行偏移和運算,所以Go語言中的指針操做很是簡單,只須要記住兩個符號:&(取地址)和*(根據地址取值)。
也須要記得:
值類型有:int、float、bool、string、array、struct
引用類型有:指針,map,切片,chan

1.1指針地址和指針類型

每一個變量在運行時都擁有一個地址,這個地址表明變量在內存中的位置。
Go語言中使用&字符放在變量前面對變量進行「取地址」操做。
Go語言中的值類型(int,float,bool,string,array,struct)都有對應的指針類型,如*int,*in64,*string等。

取變量指針的語法以下:
ptr := &v    // v的類型爲T

其中:
v:表明被取地址的變量,類型爲T
ptr:用於接收地址的變量,ptr的類型就是*T,稱做T的指針類型。*表明指針。

package main

import "fmt"

func main() {
    a:=10
    b:=&a
    fmt.Printf("a:%d ptr:%p\n",a,&a)
    fmt.Printf("b:%p type:%T\n",b,b)
    fmt.Println(&b)
}
結果:
a:10 ptr:0xc000054080
b:0xc000054080 type:*int
0xc000080018

Process finished with exit code 0

8.Go語言基礎之指針

1.2指針取值

在對普通變量使用&操做符取地址後,會得到這個變量的指針,而後能夠對指針使用*操做,即指針取值。

package main

import "fmt"

func main() {
    a:=10
    b:=&a
    fmt.Printf("type of b:%T\n",b)
    c:=*b
    fmt.Printf("type of c:%T\n",c)
    fmt.Printf("value of c:%v\n",c)
}
結果:
type of b:*int
type of c:int
value of c:10

Process finished with exit code 0
總結:
取地址操做符&和取值操做符*是一對互補操做符,&取出地址,*根據地址取出地址指向的值。
變量、指針地址、指針變量、取地址、取值的相互關係和特性以下:
1.對變量進行取地址(&)操做,能夠獲取這個變量的指針變量。
2.指針變量的值是指針地址。
3.對指針變量進行取值(*)操做,能夠得到指針變量指向的原變量的值。
package main

import "fmt"

func modify1(x int)  {
    x = 100
}
func modify2(x *int)  {
    *x = 100
}
func main() {
    a:=10
    modify1(a)
    fmt.Println(a)//10
    modify2(&a)
    fmt.Println(a)//100
}

1.3new和make

先看一個例子:

func main() {
    var a *int
    *a = 100
    fmt.Println(*a)

    var b map[string]int
    b["沙河娜扎"] = 100
    fmt.Println(b)
}

結果:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x494aaa]

goroutine 1 [running]:
main.main()
    C:/Users/Administrator/Desktop/go/src/myproject1/test.go:7 +0x2a

Process finished with exit code 2

上面的代碼引起了panic,在Go語言中,對於引用類型的變量,咱們在使用的時候不只要聲明它,還要爲它分配內存空間,不然咱們值就沒辦法存儲。
對於值類型的聲明,不須要分配內存空間,由於在聲明的時候,已經默認分配好了內存空間。
要分配內存,就引出了new和make,Go語言中使用new和make來分配內存。

1.3.1new

new是一個內置函數,它的函數簽名以下:
func new(Type) *Type
其中,
Type表示類型,new函數只接收一個參數,這個參數是一個類型。
*Type表示指針類型,new函數返回一個指向該類型內存地址的指針。
new函數不太經常使用,使用new函數獲得的是一個類型的指針,而且該指針對應的值爲該類型的零值。

package main

import "fmt"

func main() {
    a:=new(int)
    b:=new(bool)
    fmt.Printf("%T\n",a)//*int
    fmt.Printf("%T\n",b)//*bool
    fmt.Println(*a)//0
    fmt.Println(*b)//false
}
本節開始的示例代碼中,var a *int只是聲明瞭一個指針變量a,可是沒有初始化,指針做爲引用類型,須要初始化後才能擁有內存空間,才能給它賦值。
應該按照以下方式,使用內置的new函數對a進行初始化後才能夠正常進行賦值。

func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a)
}

1.3.2make

make也是用於內存分配的,與new相比,make只用於slice、map及chan的內存建立,並且它的返回類型就是三個類型自己,不是他們的指針類型,
由於這三種類型就是引用類型,因此不必返回指針了。
make函數的函數簽名以下:
func make(t Type, size ...IntegerType) Typ

make函數是無可替代的,咱們在使用slice、map、及channel的時候,都要使用make進行初始化,而後才能夠對它們進行操做。channel咱們稍後講解。

本節開始的實例中var b map[string]int只是聲明變量b是一個map類型的變量,須要像下面的示例代碼同樣使用make函數進行初始化操做後,才能對其進行鍵值對賦值。

func main() {
    var b map[string]int
    b = make(map[string]int, 10)
    b["沙河娜扎"] = 100
    fmt.Println(b)
}
new與make的區別
1.二者都是用來作內存分配的。
2.make只用於slice、map及channel的初始化,返回的仍是三中類型自己。
3.new用於類型的內存分配,而且內存對應的值爲類型零值,返回的是指向類型的指針。
相關文章
相關標籤/搜索