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) }