2016-08-24 47 views
4

我創建了一個基於Golang net.IP類型的自定義類型。令我驚訝的是,使用指針接收器聲明的方法不能修改接收者指向的值。Golang非結構型指針接收器

此代碼段中的u變量在致電u.defaultIP()後仍爲nil。如果我將自定義類型更改爲具有IP字段的結構,並且該方法使用指向結構的指針接收器定義,則可以修改IP。我錯過了什麼?可執行示例可以在here找到。

type userIP net.IP 

func main() { 
    var u *userIP 
    u.defaultIP() 
    fmt.Printf("%v\n", u) 
} 

func (u *userIP) defaultIP() { 
    defaultIP := userIP("127.0.0.1") 
    u = &defaultIP 
} 

回答

5

在設置它的值之前,需要先解除引用u

從你的榜樣,改變

defaultIP := userIP("127.0.0.1") 
u = &defaultIP 

*u = userIP("127.0.0.1") 

對於示例更新和工作:https://play.golang.org/p/ycCLT0ed9F

+1

解除引用*(我試過編輯它,但它不允許我,因爲更改少於6個字符) – Kul

+0

讀者需要點擊鏈接才能理解此答案。 (除非你已經知道解除引用的意思,但即便如此,你如何做到這一點在golang中點擊鏈接找出:D – Jacob

1

TL; DR:指針接收器需要它的價值之前被取消引用可以設置。這適用於結構和非結構類型。在結構類型的情況下,解引用是由選擇器表達式自動完成的。

經過深入挖掘,我認爲這種行爲是由於指針接收器不是調用該方法的同一指針引起的。

運行此代碼片段顯示main()函數中的u指針與defaultIP()方法中的指針不同。實質上,我最終只能修改方法中的u指針。可執行示例可以找到here

func main() { 
    var u *userIP   
    u.defaultIP() 

    fmt.Printf("main(): address of pointer is %v\n", &u) 
    fmt.Printf("main(): user IP address is %v\n", u) 
} 

type userIP net.IP 

func (u *userIP) defaultIP() { 
    defaultIP := userIP("127.0.0.1") 
    u = &defaultIP 

    fmt.Printf("defaultIP(): address of pointer is %v\n", &u) 
    fmt.Printf("defaultIP(): user IP address is %s\n", *u) 
} 

正確的方法做,這是爲指向湯姆的回答,即取消引用的defaultIP()方法u

我之前感到困惑的是,爲什麼如果我將IP作爲字段包裝在結構中時,此示例會起作用?運行代碼片段顯示兩個u指針確實不同,但ip字段被修改。可執行的例子可以發現here

func main() { 
    u := &userInfo{} 
    u.defaultIP() 

    fmt.Printf("main(): address of pointer is %v\n", &u) 
    fmt.Printf("main(): user IP address is %s\n", u.ip) 
} 

type userInfo struct{ 
    ip net.IP 
} 

func (u *userInfo) defaultIP() { 
    u.ip = net.ParseIP("127.0.0.1") 
    fmt.Printf("defaultIP(): address of pointer is %v\n", &u) 
    fmt.Printf("defaultIP(): user IP address is %s\n", u.ip) 
} 

原來,這是由selector expressionx.y)引起的。引用該文檔,

選擇器自動將指針指向結構體。如果x是指向結構體的指針,則x.y是(x).y的簡寫形式;如果字段y也是指向結構體的指針,則x.y.z是((* x).y).z的簡寫形式,依此類推。如果x包含類型* A的匿名字段,其中A也是結構類型,則x.f是(* x.A).f的快捷方式。

所以在我的情況下,u.ip表達修改ip領域,基本上轉化爲(*u).ip之前取消引用u

0

兩個選項:

1-隨着解引用:像這樣工作的代碼,並使用net.ParseIP("127.0.0.1")
The Go Playground):

package main 

import (
    "fmt" 
    "net" 
) 

type userIP net.IP 

func main() { 
    var u userIP 
    u.defaultIP() 
    fmt.Println(u) 
} 

func (u *userIP) defaultIP() { 
    *u = userIP(net.ParseIP("127.0.0.1")) 
} 

輸出:

[0 0 0 0 0 0 0 0 0 0 255 255 127 0 0 1] 

2-不需要解除引用(The Go Playground):

package main 

import (
    "fmt" 
    "net" 
) 

type userIP net.IP 

func main() { 
    u := make(userIP, 4) 
    u.defaultIP() 
    fmt.Printf("%v\n", u) 
} 

func (u userIP) defaultIP() { 
    u[0], u[1], u[2], u[3] = 127, 0, 0, 1 
} 

並注意net.IP[]byte,看到net.IP文檔:

的IP是一個單一的IP地址,字節的片。此 軟件包中的函數接受4字節(IPv4)或16字節(IPv6)片作爲輸入。

+0

使用'u =&defaultIP'是我的問題。沒有取消引用的'* u', userIP {127,0,0,1}'不起作用 –

+0

'userIP(「127.0.0.1」)'很好,請參考Tom的回答https://play.golang.org/p/ycCLT0ed9F。 –

+0

@ isim你可以使用'net.ParseIP(「127.0.0.1」)或'userIP {127,0,0,1}' – 2016-08-24 05:13:24