指针就是存储变量内存地址的变量,指针也是一种变量,我们称之为指针变量
声明一个 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 100Go语言中类型指针不能进行偏移和运算
因为这样的语言特点,带来的优势是指针变量高效的访问, 但又不会发生指针偏移,同时垃圾回收也比较容易
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