pointer
前言
每个变量除了有变量名 变量值 还有内存地址
指针本质就是内存地址
指针在C, C++, C#是非常重要的概念,由于指针可以进行运算( ++
--
平移),利用指针我们可以用非常简短的代码完成很多骚操作
pointer in golang
golang中的指针并没有C那么强大,它不能进行算术运算
取地址,变量前加&
即可
package main
import "fmt"
func main() {
name:="飞雪无情"
nameP:=&name //取地址
fmt.Println("name变量的值为:",name)
fmt.Println("name变量的地址为:",nameP)
}
下图演示指针变量 普通变量 内存地址 和 内存之间的关系:
指针是非常廉价的,占用的资源非常少
在golang中使用类型名称前加*
的方式即可表示一个对应的指针类型,eg: *string
,*int
不同指针类型无法相互赋值:比如你不能对一个string类型的变量取地址,然后赋值给*int
的指针类型,这时编译器会告诉你无法进行类型转换
name := "scott"
var intP *int
intP = &name //指针类型不同,无法赋值
需要注意的是用var关键字来定义指针变量的时候是不能直接赋值和取值的,因为这时它仅仅是一个变量,还没有对应的内存地址,它的值为nil
和普通类型不一样的是,指针类型还可以通过new关键字来声明,如下代码所示:
intP:= new(int)
内置的new函数,它有个参数,你可以传递一个类型给它,它返回的就是一个对应的指针类型
指针的操作
- 获取指针指向的值
- 修改指针指向的值
package main
import "fmt"
func main() {
name:="Scott"
var p = new(string)
p = &name
fmt.Println("获取指针变量的值:",*p)
*p = "scott123"
fmt.Println("修改指针变量的值:",*p)
}
指针参数
我们来看一个例子:
package main
import "fmt"
func main() {
age := 18
modifyAge(age)
fmt.Println("age:",age) //18
}
func modifyAge(age int) {
age = 20
}
为什么age修改不了,因为age实参只是拷贝而已,就是值传递
如果你想修改age,则需要传入指针
改造代码,再试,发现修改成功了
package main
import "fmt"
func main() {
age := 18
modifyAge(&age)
fmt.Println("age:",age) //20
}
func modifyAge(age *int) {
*age = 20
}
在函数中,通过形参去改变实参值的时候,你就需要指针类型的参数
指针的接收者
对于是否使用指针类型作为接收者,有以下几点参考
因为内存的拷贝很廉价,效率会比较高
指针注意事项
在golang中使用指针,需要注意以下细节:
1,可以通过指针改变指向值
package main
import (
"fmt"
)
func main() {
var a int = 10
fmt.Println(a) //10
var ptr *int = &a
*ptr++
fmt.Println(a) //11
*ptr = 100
fmt.Println(a) //100
}
2,指针变量一定接受的是地址值
3,指针变量的类型不可以不匹配
4,基本数据类型(又叫值类型),都有对应的指针类型,形式为*数据类型
: 比如int对应的指针就是*int
,float32对应的指针就是*float32
,以此类推
指针在golang中的好处:
- 修改指向数据的值
- 在变量赋值,参数传递的时候节约内存
go语言对指针做了诸多限制,eg 不能对指针进行运算,不能对常量使用指针
什么情况下使用指针
指针通过.
是可以直接访问成员变量的
举例如下:
type A struct{
b string
c int
}
a := &A{}
fmt.Println(a.b) //这里是不会报错的
指针在访问内部成员时,编译器会自动帮我们转化为值类型,所以你写成a.b
程序不会报错, 但是在C C++中,你必须写成a->b
才行