go基础知识(二)指针
Go 语言的取地址符是 &,变量在内存中有个地址,指针就是保存的这个地址。
1:获取变量内存地址:
package main
import "fmt"
func main(){
a := 10
fmt.Printf("变量a的内存地址是:%x\n",&a)
}2:指针
func main(){
a := 10
p := &a //取地址
fmt.Println(*p) //取值
}& 取得变量 a 的内存地址,然后通过 * 从地址中把值取出来,又叫指针取值! * 不仅可以取值,还可以修改值。
3:数组指针和指针数组
指针数组:
package main
import "fmt"
func main(){
var a = [4]string{"abc","def","ghi","123"}
// string 指针数组
var b [4]*string
fmt.Printf("%T,%v \n",b,b) //打印类型和值
for i := 0; i<4; i++{
/*
因为 b 是指针数组,所以不能直接赋值,这里赋予 a 数组地址
执行后,b 数组保存的就是数组的元素内存地址
*/
b[i] = &a[i]
}
fmt.Printf("%T,%v \n",b,b)
//便利指针数组,打印数组元素值
for _,v :=range b{
fmt.Println(*v)
}
}
数组指针
package main
import "fmt"
func main(){
x,y,z :=1,2,3
var a *[3]int = &[3]int{x,y,z}//数组指针
var b [3]*int = [3]*int{&x,&y,&z}//指针数组
fmt.Println(a,"\n",b)
} 以上输出:&[1 2 3] [0xc00005e080 0xc00005e088 0xc00005e090]
func main(){
x, y := 10, 20
a := [...]*int{&x, &y} //指针数组
b := &a //数组指针
fmt.Println(a,"\n",b)
}综合:数组指针:指向数组地址的指针
指针数组:多个数组指针(数组有多少元素就有多少指针)
4:函数指针传值
如果函数类型定义为指针类型,那么就可以给函数传递指针。
package main
import "fmt"
func main(){
x,y :=1,2
//函数为指针类型,所以传递地址
swap(&x,&y)
}
//x和y为int的指针类型
func swap(x *int,y *int){
fmt.Println(*x,*y) //打印值
}值传递
package main
import "fmt"
func add(a int)int{
a = a+1
return a
}
func main(){
var x int = 3
fmt.Println("x=",x) //这里是3
var x1 int = add(x) // x 传到add方法中变成了4
fmt.Println("x=",x) // 但这里还是 3
}因为值传递是内存中复制一份,被调用的函数(这里是add)参数中发送了变化,不会导致原函数(这里是main)变量的值改变。传递指针
package main
import "fmt"
func add(a *int)int{
*a = *a+1
return *a
}
func main(){
x :=3
fmt.Println("x=",x) //这里是3
add(&x) //传递地址,在add中地址赋予了新值
fmt.Println("x=",x) //这里变成了4
}可以看到实参原来为3,但是传递之后,实参也变成了4,这是因为两个参数的内存地址是一样的。
总结:
值传递:x的值传递给a,内存中复制了一份,这样内存中的地址是不同的,值也就不一定相同
传递指针:x 的内存地址传给了 a,这样两个变量在内存中的地址是一样的,也就是两个变量指向了内存中的一个地址,所以值也是一样的。
5:结构体方法
package main
import "fmt"
// 定义结构体 Student
type Student struct{
Id int
Name string
}
/*
结构体Student中的方法See
这里有个*号,表明接受者为指针类型
*/
func (m *Student) See() {
m.Name = "李小龙"
fmt.Println(m.Name)
//这里是否发现一个问题?我们取指针的值是用 * ,但是结构体指针,我们不要*取值赋值,直接使用.
}
func main(){
//结构体赋值
StudentVlues := Student{Id:1,Name:"李连杰",}
// 上面是传值,下面是传地,但都是一样的。
// 因为接受者是指着类型,如果是传值,go内部会转换成地址
//StudentVlues := &Student{Id:1,Name:"李连杰",}
StudentVlues.See() //调用 See 方法
fmt.Println(StudentVlues.Name)
}