2016-08-24 2 views
4

Я создал собственный тип, основанный на типе Golang net.IP. Меня удивило то, что метод, объявленный с помощью получателя указателя на мой собственный тип, не может изменить значение, на которое указывает приемник.Golang Non-Struct Type Pointer Receiver

Переменная в этом фрагменте кода остается nil после звонка u.defaultIP(). 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

dereference * (я пробовал редактировать это, но это не позволяло мне, так как изменение было менее 6 символов) – Kul

+0

Читателю нужно нажать на ссылку, чтобы понять этот ответ. (если вы уже не знаете, что означает разыменование, но даже так, как вы это делаете в golang-клике по ссылке, чтобы узнать: D – Jacob

1

TL; DR: Приемник указателя должен быть разыменовываются, прежде чем это значение могут быть установлены. Это относится как к структурным, так и к неструктурным типам. В случае типов структур разыменование автоматически выполняется выражением селектора.

После того, как я немного углубился, я думаю, что это поведение вызвано тем, что приемник указателя не является тем же самым указателем, вызывающим метод.

Выполнение этого фрагмента кода показывает, что указатель u в функции main() отличается от функции defaultIP(). По сути, я заканчиваю только, изменяя указатель u в методе defaultIP(). Исполняемый пример можно найти 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) 
} 

правильный способ сделать это как указано в ответе Тома есть разыменовать u в методе defaultIP().

Что меня озадачило раньше, почему этот пример будет работать, если я завернул 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 expression (x.y). Для цитирования документа,

Селекторы автоматически разыменовывают указатели на структуры. Если x является указателем на структуру, x.y является сокращением для (x) .y; если поле y также является указателем на структуру, x.y.z является сокращением для ( (* x) .y) .z и т. д. Если x содержит анонимное поле типа * A, где A также является типом структуры, x.f является ярлыком для (* x.A) .f.

Так что в моем случае, выражение u.ip разыменовывает u перед изменением ip поля, которое по существу переводит к (*u).ip.

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 Docs:

IP-это один IP-адрес, кусочком байтов. Функции в этом пакете принимают в качестве входных данных 4-байтовые (IPv4) или 16-байтовые (IPv6) фрагменты.

+0

Использование 'u = & defaultIP' - моя проблема. Без разыменованных' * u', ' userIP {127, 0, 0, 1} 'не будет работать. –

+0

' userIP ("127.0.0.1") 'отлично. Обратитесь к ответу Тома на странице https://play.golang.org/p/ycCLT0ed9F. –

+0

@ isim Вы можете использовать 'net.ParseIP (" 127.0.0.1 ")' или 'userIP {127, 0, 0, 1}' –

Смежные вопросы