文章目錄
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