Golang與指針

文章目錄


在這裏插入圖片描述

1. 指針類型

指針就是存儲變量內存地址的變量,指針也是一種變量,我們稱之爲指針變量

聲明一個 T 類型的指針,指針聲明之後默認值都是nil

package main

import "fmt"

func main() {
	// 聲明一個int類型指針
	var p *int
	// 聲明一個string類型指針
	var s *string
	// 聲明一個bool類型指針
	var b *bool
	// 聲明一個interface類型指針
	var i *interface{}
	fmt.Printf("p default value = %v  p type = %T\n",p,p)
	fmt.Printf("s default value = %v  p type = %T\n",s,s)
	fmt.Printf("b default value = %v  p type = %T\n",b,b)
	fmt.Printf("i default value = %v  p type = %T\n",i,i)
}

p default value = <nil>  p type = *int
s default value = <nil>  p type = *string
b default value = <nil>  p type = *bool
i default value = <nil>  p type = *interface {}

指針的初始化和基本使用

package main

import "fmt"

func main() {
	// 聲明一個整型變量 n 並且初始化賦值爲99
	var n int = 99
	// 獲取n在內存中的地址,使用 & 符號取一個變量的地址
	fmt.Println("整型變量n的地址是 :", &n)
	// 聲明一個指針變量p 類型是int指針類型
	var p *int
	// 整數指針變量p初始化賦值,將整數變量n的地址賦給指針變量p
	p = &n
	// 打印p的值(保存的是n的內存地址)
	fmt.Println("指針變量p的值是   :", p)
	// 指針變量p本身也有一個內存地址
	fmt.Println("指針變量P本身的內存地址是", &p)
	// 通過 * 訪問指向變量的值
	fmt.Println("指針變量p指向變量的值是 :", *p)
	// 修改指針變量p指向變量n的值
	fmt.Println("整型變量n的值是", n)
	*p = 100
	// 查看n的值被改變了
	fmt.Println("修改後整型變量n的值是", n)

}

整型變量n的地址是 : 0xc000054080
指針變量p的值是   : 0xc000054080
指針變量P本身的內存地址是 0xc000080020
指針變量p指向變量的值是 : 99
整型變量n的值是 99
修改後整型變量n的值是 100

當指針變量沒有指向的時候不能進行 (*p)的操作

package main

import "fmt"

func main() {
	var p *int
    // panic: runtime error: invalid memory address or nil pointer dereference
	fmt.Println(*p)
}

也就是說指針變量要使用應該給它初始化一個內存

內置new()函數也可創建指針,new() 是一個內存分配函數,傳入的參數是一個類型,且返回指向的指針

// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type
package main

import (
	"fmt"
)

func main() {
	// 指針變量初始化方法1
	fmt.Println("指針變量初始化方法1")
	var p *int
	var i int
	fmt.Println(&i)
	p = &i
	fmt.Println(p)
	fmt.Println(*p)
	fmt.Println("指針變量初始化方法2")
	var p2 *int
	// 使用new()函數初始化
	p2 = new(int)
	fmt.Println(p2)
	fmt.Println(*p2)
	// 和上面類似就是寫法不同
	fmt.Println("指針變量初始化方法3")
	p3 := new(int)
	fmt.Println(p3)
	fmt.Println(*p3)
	// 類型推導
	var p4 = &i
	fmt.Printf("p4 value = %v ,type = %T \n",p4,p4)
}
指針變量初始化方法1
0xc000054090
0xc000054090
0
指針變量初始化方法2
0xc000054098
0
指針變量初始化方法3
0xc0000540a0
0
p4 value = 0xc000054090 ,type = *int 

指針可以指向任何類型變量,也包括指向另一個指針

package main

import "fmt"

func main(){
	var i int = 100
	var p1 = &i
	fmt.Printf("i type is %T, value = %v, memory address = %v\n",i,i,&i)
	fmt.Printf("p type is %T, value = %v, memory address = %v\n",p1,p1,&p1)
	// 創建一個指向指針的指針變量
	var p2 = &p1
	fmt.Printf("p2 type is %T, value = %v\n",p2,p2)
	// 訪問的是p1變量的值,而p1也是指針變量,它的值就是一個內存地址
	fmt.Println(*p2)
	// 等價於 *p1 最終訪問的是整型變量i的值
	fmt.Println(**p2)
	fmt.Println(*(*p2))
}

i type is int, value = 100, memory address = 0xc000054080
p type is *int, value = 0xc000054080, memory address = 0xc000080018
p2 type is **int, value = 0xc000080018
0xc000054080
100
100

Go語言中類型指針不能進行偏移和運算

因爲這樣的語言特點,帶來的優勢是指針變量高效的訪問, 但又不會發生指針偏移,同時垃圾回收也比較容易

package main

import "fmt"

func main() {
	var i int = 98
	var p *int = &i
	var p1 = &i
	// invalid operation: p + p1 (operator + not defined on pointer)
	var p2 = p + p1
	//invalid operation: p1 + 2 (mismatched types *int and int)
	var p3 = p1 + 2
	fmt.Println(p1)
}

指針變量可以使用關係運算符 == 比較 ,但是不能進行 > 或者 < 比較

package main

import "fmt"

func main() {
	var i1 int8 = 90
	var i2 int64 = 80
	var i3 int8 = 70
	var p1 *int8 = &i1
	var p2 *int64 = &i2
	var p3 = &i2
	var p4 = &i3
	fmt.Println(p1)
	fmt.Println(p2)
	fmt.Println(p3)
	// p2 == p3
	if p2 == p3 {
		fmt.Println("p2 == p3")
	}
	//invalid operation: p2 > p1 (mismatched types *int64 and *int8)
	if p2 > p1 {
		fmt.Println("")
	}
	// invalid operation: p1 < p4 (operator < not defined on pointer)
	if p1 < p4{
		fmt.Println("p1 < p4")
	}

}

指針可以作爲參數傳遞

package main

import "fmt"

// 函數的形參是一個整型指針類型
func modifyVar(p *int) {
	*p += 100
}
func exchangevar(i, j *int) {
	*i, *j = *j, *i
}
func main() {
	var i int = 1
	fmt.Println(i)
	modifyVar(&i)
	fmt.Println(i)
	var x, y int = 66, 99
	// 交換前的值
	fmt.Println("x = ", x)
	fmt.Println("y = ", y)
	// 交換後的值
	exchangevar(&x, &y)
	fmt.Println("x = ", x)
	fmt.Println("y = ", y)
}

1
101
x =  66
y =  99
x =  99
y =  66

案例: 使用指針變量獲取命令行輸入信息

package main

import (
	"flag"
	"fmt"
)
//定義一個叫做mode的指令變量 *string類型
var mode = flag.String("mode","","process mode")
func main() {
	// 解析命令行參數,將結果寫入創建的指令變量中
	flag.Parse()
	if *mode == "fast"{
		fmt.Println("fast mode execute")
	}else if *mode == "slow" {
		fmt.Println("slow mode execute")
	}else {
		fmt.Println("default mode execute")
	}
}
$ go run main.go --mode=fast
fast mode execute
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章