从JAVA和JS转过来的苦逼工程师,因为以上两门语言,一般情况下是没有指针的说法的,所以现在用go一通折腾,有时候就是引用指针傻傻分不清楚,或者声明指针未初始化报错的问题。不得已,写下此博客,记录自己菜鸟之路。
指针
// 定义一个结构体
type Person struct{
Name string
Age int
}
var Pperson *Person // 声明类型为Person的指针
// fmt.Println(Pperson.Name) // 此时会报错,因为Pperson为nil,所以无论如何,要使用指针类型,必须先初始化!!!
Pperson = new(Person) // go中 new(type) 返回的是指针
Pperson = &Person{} // 或者这种方式初始化
结构体和函数
func (p Person) SetName(name string){
p.Name=name
}
func (p *Person) SetNameP (name string){
p.Name=name
}
func main(){
person := Person{Name:"Jon",}
fmt.Println(person.Name) //Jon
person.SetName("Tom")
fmt.Println(person.Name) //Jon
person.SetNameP("Tom")
fmt.Println(person.Name) //Tom
}
只是一个在JAVA看起来很奇怪的问题,在面向对象语言的思维中,结果应该是 Jon /Tom / Tom,原因在于Golang的指针类型和值类型。
func (p Person) SetName(name string)
在调用的时候,实际是把 person 拷贝了一份 ,然后再函数里面对拷贝的变量进行赋值,结果并未改变原来的值。
func (p *Person) SetNameP (name string)
相当于把person的指针传入了函数内,然后在函数内通过指针改变了值真实地址内部的Name
值,所以才能打印出Tom。
下面是另外一种情况,对指针不熟悉的人可能会糊涂
type data struct {
num int
key *string
}
func (this *data) pointerFunc() {
this.num = 7
}
func (this data) valueFunc1() {
this.num = 8
str := "valueFunc.key"
*this.key = str
}
func (this data) valueFunc2() {
this.num = 8
str := "valueFunc.key"
this.key = &str
}
func main() {
key := "key1"
d := data{1, &key}
fmt.Printf("num=%v key=%v \n", d.num, *d.key)
d.pointerFunc() // 修改 num 的值为 7
fmt.Printf("num=%v key=%v \n", d.num, *d.key)
d.valueFunc2() // 修改 key 和 items 的值
fmt.Printf("num=%v key=%v \n", d.num, *d.key)
d.valueFunc1() // 修改 key 和 items 的值
fmt.Printf("num=%v key=%v \n", d.num, *d.key)
}
结果:
num=1 key=key1
num=7 key=key1
num=7 key=key1
num=7 key=valueFunc.key
在valueFunc2
中,相当也复制了一份data,然后改变了data的key的指针本身,所以不影响原值,在valueFunc1
中,虽然也是复制原值,但是因为复制的是key的指针也复制了一份,但是这里改变的是key指针指向的内容,而这个指针也是原值的指针,所以对应的,原值的key也表了。