指针
一、什么是指针
-
指针也是一种变量,但是它的功能只是用来存储变量内存地址(Memory Address),即指针变量的值为其他变量的内存地址
-
指针是变量,所以它本身也有内存地址
-
内存地址都是属于
int
类型的值 -
Go中的指针是不支持运算的(有些语言可以,如C语言)
-
package main func main() { b := [...]int{109, 110, 111} p := &b p++ // 不能进行运算,会报错 main.go:6: invalid operation: p++ (non-numeric type *[3]int) }
-
二、指针的定义
-
最关键的两个符合
&
表示取变量的内存地址,*
表示通过地址找到值
-
指针变量的类型为
*T
,T为数据类型 -
指针的空值为
nil
1. 指针的声明
var d *string // 声明了一个指针类型的字符串,恒等于 nil
var f *[3]int // 声明了一个指针类型的数组,恒等于 nil
var g *[]int // 声明了一个指针类型的切片,恒等于 nil
package main
import (
"fmt"
)
2. 指针实例
func main() {
b := 255
a := &b // & 表示取变量的内存地址
fmt.Println("address of b is", a)
fmt.Println("value of b is", *a) // * 表示取指针的指向的值
}
/*
打印结果:
address of b is 0x1040a124
value of b is 255
*/
三、向函数传递指针参数
- 分为三种类型的指针参数
- 数字、字符串类型的指针
- 数组类型的指针(不推荐,推荐替换为直接传切片)
- 切片类型(切片类型无需传递其指针,用来替代数组类型指针)
1. 传入字符串类型的指针
package main
import (
"fmt"
)
func change(val *int) {
*val = 55
}
func main() {
a := 58
fmt.Println("value of a before function call is", a)
b := &a
change(b)
fmt.Println("value of a after function call is", a)
}
/*
value of a before function call is 58
value of a after function call is 55
可以看到,在函数中修改了传入的参数,但是,在函数外,a的值也同步被修改了
若不用指针,直接将a传入函数,则最后打印的a 仍是 58
*/
2. 传入数组类型的指针
- 假如我们想在函数内部修改一个数组,并希望函数外部的数组也同步修改,有两种方式
- 一种解决方案是把一个指向数组的指针传递给这个函数
- 另一种是传递该数组的切片(因为切片的结构就包括底层数组的指针,其本身没有值)
- 且传递数组类型的指针时,在函数内部,无需用符号
*
进行取值,可直接将参数当数组使用,Go的语法糖
package main
import (
"fmt"
)
func modify(arr *[3]int) { // 接收 数组类型的指针 参数
arr[0] = 90 // 本来应该写成 (*arr)[0] = 90 ,但是 go对数组指针做个处理
}
func main() {
a := [3]int{89, 90, 91}
modify(&a)
fmt.Println(a) // [90 90 91] ,可以看到数组a的第一个元素也被修改为90了
}
3. 传入切片
- 传入切片类型,能使得代码更加简洁,且更符合Go语言的习惯
package main
import (
"fmt"
)
func modify(sls []int) { // 接收 切片类型 参数
sls[0] = 90
}
func main() {
a := [3]int{89, 90, 91}
modify(a[:])
fmt.Println(a) // [90 90 91] ,传切片时,数组a的第一个元素也被修改为90了
}