【高级数据类型2】- 11. 指针

Go语言-指针

    

    先了解下变量&地址&指针的关系点击跳转去看数组

 

    咱们在前面屡次提到过指针及指针类型。例如,*PersonPerson的指针类型。又例如,表达式&p的求值结果是p的指针。方法的接收者类型的不一样会给方法的功能带来什么影响?该方法所属的类型又会所以发生哪些潜移默化的改变?如今,咱们就来解答第一个问题。至于第二个问题,我会在下一小节予以解答。ui

    指针操做涉及到两个操做符——&*。这两个操做符均有多个用途。可是当它们做为地址操做符出现时,前者的做用是取址,然后者的做用是取值。更通俗地讲,当地址操做符&被应用到一个值上时会取出指向该值的指针值,而当地址操做符*被应用到一个指针值上时会取出该指针指向的那个值。它们能够被视为相反的操做。
  
    除此以外,当*出如今一个类型以前(如*Person*[3]string)时就不能被看作是操做符了,而应该被视为一个符号。如此组合而成的标识符所表达的含义是做为第二部分的那个类型的指针类型。咱们也能够把其中的第二部分所表明的类型称为基底类型。例如,*[3]string是数组类型[3]string的指针类型,而[3]string*[3]string的基底类型。
  
    好了,咱们如今回过头去再看结构体类型Person。它及其两个方法的完整声明以下:spa

type Person struct {
    Name    string
    Gender  string
    Age     uint8
    Address string
}

func (person *Person) Grow() {
    person.Age++
}

func (person *Person) Move(newAddress string) string {
    old := person.Address
    person.Address = newAddress
    return old
}

    注意,Person的两个方法GrowMove的接收者类型都是*Person,而不是Person。只要一个方法的接收者类型是其所属类型的指针类型而不是该类型自己,那么我就能够称该方法为一个指针方法。上面的Grow方法和Move方法都是Person类型的指针方法
  
    相对的,若是一个方法的接收者类型就是其所属的类型自己,那么咱们就能够把它叫作值方法。咱们只要微调一下Grow方法的接收者类型就能够把它从指针方法变为值方法:.net

func (person Person) Grow() {
    person.Age++
}

    那指针方法和值方法到底有什么区别呢?咱们在保留上述修改的前提下编写以下代码:指针

p := Person{"Robert", "Male", 33, "Beijing"}
p.Grow()
fmt.Printf("%v\n", p)

    这段代码被执行后,标准输出会打印出什么内容呢?直觉上,34会被打印出来,可是被打印出来的倒是33。这是怎么回事呢?Grow方法的功能失效了?!
  
    解答这个问题须要引出一条定论:方法的接收者标识符所表明的是该方法当前所属的那个值的一个副本,而不是该值自己。例如,在上述代码中,Person类型的Grow方法的接收者标识符person表明的是p的值的一个拷贝,而不是p的值。咱们在调用Grow方法的时候,Go语言会将p的值复制一份并将其做为这次调用的当前值。正由于如此,Grow方法中的person.Age++语句的执行会使这个副本的Age字段的值变为34,而pAge字段的值却依然是33。这就是问题所在。
  
    只要咱们把Grow变回指针方法就能够解决这个问题。缘由是,这时的person表明的是p的值的指针的副本。指针的副本仍会指向p的值。另外,之因此选择表达式person.Age成立,是由于若是Go语言发现person是指针而且指向的那个值有Age字段,那么就会把该表达式视为(*person).Age。其实,这时的person.Age正是(*person).Age的速记法。code

 

 

我的最后结果:点击跳转去看blog

相关文章
相关标签/搜索