英文:
Why can't I append to a slice that's the property of a struct in golang?
问题
我正在尝试将一个值追加到 Golang 切片中,如果在第一个方法中调用该代码,它可以正常工作,但如果该方法调用另一个方法,代码似乎会失败。
以下是示例代码(Test3 是我最初尝试的):
package main
import (
"fmt"
)
// 这个可以正常工作
type Test1 struct {
all []int
}
func (c Test1) run() []int {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
}
return c.all
}
// 这个可以正常工作
var gloabl_all []int
type Test2 struct{}
func (c Test2) run() []int {
c.combo()
return gloabl_all
}
func (c Test2) combo() {
for i := 0; i < 2; i++ {
gloabl_all = append(gloabl_all, i)
}
}
// 这个不行
type Test3 struct {
all []int
}
func (c Test3) run() []int {
c.combo()
return c.all
}
func (c Test3) combo() {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
fmt.Println("Test3 step", i+1, c.all)
}
}
func main() {
test1 := &Test1{}
fmt.Println("Test1 final:", test1.run(), "\n")
test2 := &Test2{}
fmt.Println("Test2 final:", test2.run(), "\n")
test3 := &Test3{}
fmt.Println("Test3 final:", test3.run())
}
这将输出:
Test1 final: [0 1]
Test2 final: [0 1]
Test3 step 1 [0]
Test3 step 2 [0 1]
Test3 final: []
你需要帮助吗?
英文:
I'm trying to append a value to a golang slice, the code works if it's called in the first method, but if this method calls another method, the code seems to fail.
Examples (Test3 is what I was originally trying to do):
package main
import (
"fmt"
)
// This works
type Test1 struct {
all []int
}
func (c Test1) run() []int {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
}
return c.all
}
// This works
var gloabl_all []int
type Test2 struct {}
func (c Test2) run() []int {
c.combo()
return gloabl_all
}
func (c Test2) combo() {
for i := 0; i < 2; i++ {
gloabl_all = append(gloabl_all, i)
}
}
// This doesn't
type Test3 struct {
all []int
}
func (c Test3) run() []int {
c.combo()
return c.all
}
func (c Test3) combo() {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
fmt.Println("Test3 step", i + 1, c.all)
}
}
func main() {
test1 := &Test1{}
fmt.Println("Test1 final:", test1.run(), "\n")
test2 := &Test2{}
fmt.Println("Test2 final:", test2.run(), "\n")
test3 := &Test3{}
fmt.Println("Test3 final:", test3.run())
}
This outputs:
Test1 final: [0 1]
Test2 final: [0 1]
Test3 step 1 [0]
Test3 step 2 [0 1]
Test3 final: []
Playground copy: https://play.golang.org/p/upEXINUvNu
Any help would be greatly appreciated!
答案1
得分: 13
Go语言中的一切都是按值传递的。传递的值会被复制。
Test3.combo()
使用值(非指针)接收器:
func (c Test3) run() []int {
c.combo()
return c.all
}
func (c Test3) combo() {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
fmt.Println("Test3 step", i + 1, c.all)
}
}
这意味着当从Test3.run()
中调用Test3.combo()
时,会对c
(类型为Test3
)进行复制。combo()
方法在复制上操作。它正确地将2个数字附加到Test3.all
,但当该方法返回时,复制被丢弃。
因此,当Test3.run()
返回c.all
时,它返回一个空(nil
)切片,因为Test3.combo()
附加的切片是复制的字段,而该复制已被丢弃。
解决方法:简单地使用指针接收器:
func (c *Test3) combo() {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
fmt.Println("Test3 step", i + 1, c.all)
}
}
输出(在Go Playground上尝试):
Test1 final: [0 1]
Test2 final: [0 1]
Test3 step 1 [0]
Test3 step 2 [0 1]
Test3 final: [0 1]
注意接收器中的星号*
:func (c *Test3) combo()
。通过添加它,您使接收器成为一个指针,因此当调用combo()
时,它只接收指向类型为Test3
的值的指针,并且它将修改指向的值,即Test3.run()
拥有的值,因此当combo()
返回时,更改不会丢失。
英文:
Everything in Go is passed by value. And a copy is made of the passed value.
Test3.combo()
has value (non-pointer) receiver:
func (c Test3) run() []int {
c.combo()
return c.all
}
func (c Test3) combo() {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
fmt.Println("Test3 step", i + 1, c.all)
}
}
This means when Test3.combo()
is called from Test3.run()
like c.combo()
, a copy is made of c
(which is of type Test3
). The combo()
method operates on a copy. It properly appends 2 numbers to Test3.all
, but when this method returns, the copy is discarded.
So when Test3.run()
returns c.all
, it returns an empty (nil
) slice, because the slice to which Test3.combo()
appended, was a field of a copy, and which has been discarded.
Solution: simply use a pointer receiver:
func (c *Test3) combo() {
for i := 0; i < 2; i++ {
c.all = append(c.all, i)
fmt.Println("Test3 step", i + 1, c.all)
}
}
Output (try it on the Go Playground):
Test1 final: [0 1]
Test2 final: [0 1]
Test3 step 1 [0]
Test3 step 2 [0 1]
Test3 final: [0 1]
Note the star *
in the receiver: func (c *Test3) combo()
. By adding it, you make the receiver a pointer, and so when combo()
is called, it only receives a pointer to a value of type Test3
, and it will modify the pointed value, the value that Test3.run()
has, so when combo()
returns, the changes are not lost.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论