Go語言基礎之指標
阿新 • • 發佈:2020-07-29
Go語言的指標不能進行偏移和計算,是安全的指標。
搞明白指標的必備三個條件:
- 指標地址
- 指標型別
- 指標取值
Go語言中的指標
一個變數在程式中都有他們的記憶體地址,這就是指標。為了儲存資料在記憶體中的地址,那麼我們就需要指標變數。
Go語言中的指標是安全的,因此我們只需要記住兩個符號& 取地址
和 * 根據地址取值
指標型別和指標地址
Go語言中的值型別(int
, float
, bool
, string
, array
, struct
)都有對應的指標型別,如:*int
, *int64
, *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) // a: 10 ptr: 0xc0000140b0 fmt.Printf("b:%p type: %T\n", b, b) // b:0xc0000140b0 type: *int fmt.Println(&b) // 0xc000006028 指標也需要一個地址去儲存 }
指標取值
在對普通變數使用&
操作符取地址後會獲得這個變數的指標,然後可以對指標使用*
操作,也就是指標取值,程式碼如下
func main() {
a := 10
b := &a
fmt.Printf("type of b: %T\n", b) // 去變數a的地址,將指標儲存到b中
c := *b // 指標取值 根據指標去記憶體取值
}
type of b:*int
type of c:int
value of c:10
總結:取地址操作符&
和取值操作符*
是一對互補操作符,&
取出地址,*
根據地址取出地址指向的值。
變數、指標地址、指標變數、取地址、取值的相互關係和特性如下:
- 對變數進行取地址(
&
)操作,可以獲得這個變數的指標變數。 - 指標變數的值是指標地址。
- 對指標變數進行取值(
*
)操作,可以獲得指標變數指向的原變數的值。
指標傳值例項
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)
modify2(&a)
fmt.Println(a)
}
new 和 make
請你們破個案
func main() {
var a *int
*a = 100
fmt.Println(*a)
} // 這個程式會打印出來啥?
// 答案是報錯了,panic: runtime error: invalid memory address or nil pointer dereference
- 為啥呢?
- 在Go語言中對於引用型別的變數,我們在使用的時候不僅要宣告它,還要為它分配記憶體空間,否則我們的值就沒辦法儲存。而對於值型別的宣告不需要分配記憶體空間,是因為它們在宣告的時候已經預設分配好了記憶體空間。要分配記憶體,就引出來今天的new和make。 Go語言中new和make是內建的兩個函式,主要用來分配記憶體。
new
new
是一個內建函式,它的簽名如下:
func new(Type) *Type
Type
表示型別,new
函式只接收一個引數,這個引數是一個型別*Type
表示型別指標,new
函式返回一個指向該型別記憶體地址的指標
new
函式不太常用,使用new
函式得到的是一個型別的指標,並且該指標對應的值為該型別的零值。
func main() {
a := new(int)
b := new(bool)
c := new(string)
fmt.Printf("%T\n", a) // *int
fmt.Printf("%T\n", b) // *bool
fmt.Printf("%T\n", c) // *string
fmt.Println(*a) // 0
fmt.Println(*b) // 此處為空字串
fmt.Println(*c) // false
}
make
make也是用於記憶體分配的,區別於new,它只用於slice
、map
以及chan
的記憶體建立,而且它返回的型別就是這三個型別本身,而不是他們的指標型別,因為這三種類型就是引用型別,所以就沒有必要返回他們的指標了。make函式的函式簽名如下:
func make(t Type, size ...IntegerType) Type
make函式是無可替代的,我們在使用slice、map以及channel的時候,都需要使用make進行初始化,然後才可以對它們進行操作。
func main() {
a := map[string]int{}
fmt.Printf("%T\n", a) //map[string]int 返回的就是本身,因為是引用型別
a["hello"] = 10
fmt.Println(a)
var b map[string]int
b = make(map[string]int, 10)
b["hello"] = 40
fmt.Println(b)
}
new
和make
的區別
- 二者都是用來做記憶體分配的
make
只用於slice
、map
以及chan
型別的初始化,返回的還是這三個型別的本身new
用於型別的記憶體分配,並且記憶體對應的值為型別零值,返回的是指向型別的指標