英文:
Golang Non-Struct Type Pointer Receiver
问题
我根据Golang的net.IP
类型创建了一个自定义类型。令我惊讶的是,使用指针接收器声明的方法无法修改接收器指向的值。
在这段代码中,调用u.defaultIP()
后,u
变量仍然是nil
。如果我将自定义类型更改为具有IP字段的结构体,并且该方法使用指针接收器定义在结构体上,那么IP可以被修改。我错过了什么?可在这里找到可执行的示例。
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
}
英文:
I created a custom type based on the Golang net.IP
type. What surprised me is that a method declared with a pointer receiver to my custom type can't modify the value to which the receiver points.
The u
variable in this code snippet remains nil
after calling u.defaultIP()
. The IP can be modified if I changed my custom type to a struct with an IP field and the method is defined with a pointer receiver to the struct. What am I missing? Executable example can be found 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
}
答案1
得分: 8
你需要在设置u
的值之前对其进行解引用。
根据你的示例,将代码修改为:
defaultIP := userIP("127.0.0.1")
u = &defaultIP
修改为:
*u = userIP("127.0.0.1")
你可以查看更新后的示例代码并测试:https://play.golang.org/p/ycCLT0ed9F
英文:
You need to dereference the u
before setting it's value.
From your example, change
defaultIP := userIP("127.0.0.1")
u = &defaultIP
to
*u = userIP("127.0.0.1")
For your example updated and working: https://play.golang.org/p/ycCLT0ed9F
答案2
得分: 2
TL;DR:在设置值之前,需要对指针接收器进行解引用。这适用于结构体和非结构体类型。对于结构体类型,解引用是由选择器表达式自动完成的。
经过进一步的调查,我认为这种行为是由于指针接收器与调用方法的指针不同所导致的。
运行这段代码片段显示,在main()
函数中的u
指针与defaultIP()
方法中的指针是不同的。实质上,我最终只修改了defaultIP()
方法中的u
指针。可在此处找到可执行的示例。
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)
}
正确的做法是如Tom的答案所指出的,在defaultIP()
方法中对u
进行解引用。
之前让我困惑的是,如果我将IP封装为结构体中的字段,为什么这个示例会起作用?运行代码片段显示,两个u
指针确实是不同的,但ip
字段被修改了。可在此处找到可执行的示例。
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)
}
原来,这是由于选择器表达式(x.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
进行了解引用,这实际上相当于(*u).ip
。
英文:
TL;DR: The pointer receiver needs to be dereferenced before it's value can be set. This applies to both struct and non-struct types. In the case of struct types, the dereferencing is automatically done by the selector expression.
After digging around a bit further, I think this behaviour is caused by the fact that the pointer receiver is not the same pointer calling the method.
Running this code snippet shows that the u
pointer in the main()
function is different from that in the defaultIP()
method. Essentially, I end up only modifying the u
pointer in the defaultIP()
method. Executable example can be found 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)
}
The correct way to do this is as pointed in Tom's answer i.e. dereference u
in the defaultIP()
method.
What puzzled me earlier was why would this example work if I wrapped the IP as a field in the struct? Running the code snippet shows that the two u
pointers are indeed different, but the ip
field is modified. Executable example can be found 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)
}
Turns out that this is caused by the selector expression (x.y
). To quote the doc,
> Selectors automatically dereference pointers to structs. If x is a pointer to a struct, x.y is shorthand for (x).y; if the field y is also a pointer to a struct, x.y.z is shorthand for ((*x).y).z, and so on. If x contains an anonymous field of type *A, where A is also a struct type, x.f is a shortcut for (*x.A).f.
So in my case, the u.ip
expression dereferences u
before modifying the ip
field, which essentially translates to(*u).ip
.
答案3
得分: 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)的切片作为输入。
英文:
Two Options:
1- With dereferencing: like this working code and using net.ParseIP("127.0.0.1")
(The Go Playground):
<!-- language: lang-golang -->
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"))
}
output:
[0 0 0 0 0 0 0 0 0 0 255 255 127 0 0 1]
2- Without dereferencing (The Go Playground):
<!-- language: lang-golang -->
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
}
And note that net.IP
is []byte
, see net.IP
Docs:
> An IP is a single IP address, a slice of bytes. Functions in this
> package accept either 4-byte (IPv4) or 16-byte (IPv6) slices as input.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论