【发布时间】:2021-04-15 08:25:23
【问题描述】:
我正在尝试遵循 Go 谚语“使零值有用”,但遇到了我的结构上默认为 nil(如 map)的私有字段的问题。如果我的结构的零值是有用的,在某些时候它需要初始化私有字段。考虑以下情况,我想取消Response 的构造函数,并使Response 的零值有用。显然需要初始化字段bag(即map[string]interface{})。当在响应上调用 getter Bag() 时,我尝试初始化字段 bag,这有效,然后允许在包上调用 Set() 以设置值。但不知何故,当响应最终回到主函数时,我的价值就丢失了。
我认为问题在于我提出的初始化替换了响应副本上的指针,而不是更改指针指向的位置。所以旧指针仍然指向nil,但我不确定。如何在没有构造函数的情况下正确初始化私有字段?
func main() {
response := getResponse()
number := response.Bag().Get("NiceNumber")
fmt.Println(response.Name, "tells me that your nice number today is:", number)
}
func getResponse() (response Response) {
response = newResponse() // I am trying to do away with this line.
response.Name = "MyResponse"
response.Bag().Set("NiceNumber", 100)
return
}
type Response struct {
Name string
bag Bag
}
func (r Response) Bag() Bag {
// I have added this piece of code as an attempt to initialize r.bag
if r.bag == nil {
r.bag = Bag(make(map[string]interface{}))
}
// ---
return r.bag
}
type Bag map[string]interface{}
func (b Bag) Set(name string, value interface{}) {
b[name] = value
}
func (b Bag) Get(name string) interface{} {
return b[name]
}
// This constructor would be deleted if possible.
func newResponse() Response {
return Response{
Name: "",
bag: Bag(make(map[string]interface{})),
}
}
现在的输出是MyResponse tells me that your nice number today is: 100,当我删除对Response的构造函数的调用时,输出是MyResponse tells me that your nice number today is: <nil>。
【问题讨论】:
-
“我认为问题在于我提出的初始化替换了 Response 副本上的指针,而不是更改指针指向的位置。” --是的,你是对的。如果您更改方法确实有一个指针接收器,即
func (r *Response) Bag() Bag {,它应该会得到您期望的结果。但请记住,由于Bag()修改了它的接收器,如果您的代码在Response而不是*Response周围传递,它仍然会以不一致的状态结束。 -
这可能会起作用,但它无助于使
Response的零值有用,即Response{}仍然无法正常工作。它还改变了 getResponse() 函数的签名,我希望尽可能避免。 -
我认为对于像这样的复杂场景,constructor 是最好的方法:stackoverflow.com/questions/27553399/… 或正如@mkopriva 所说,更改方法以接受 ptr 接收器跨度>
-
@mkopriva 我只是按照你说的方式尝试了它,它似乎有效,但我不明白为什么。如何在 Response 的非指针变量上调用 getter
Bag()?您能否将您的建议表述为一个带有一点解释的答案,以便我接受? -
@Bazzz 编译器(或运行时?我忘了)会自动执行此操作。
标签: go