【高級數據類型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

相關文章
相關標籤/搜索