为什么我不能追加到golang中结构属性的切片? [英] Why can't I append to a slice that's the property of a struct in golang?

查看:157
本文介绍了为什么我不能追加到golang中结构属性的切片?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图给golang slice添加一个值,如果代码在第一个方法中被调用,代码就会工作,但如果这个方法调用另一个方法,代码似乎就失败了。



示例(Test3就是我最初试图做的):

  package main 

导入(
fmt


//这是可行的

类型Test1结构{
all [] int
}

func(c Test1)run()[] int {
for i:= 0;我< 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;我< 2; i ++ {
gloabl_all = append(gloabl_all,i)
}
}

//这不是

类型Test3结构{
all [] int
}

func(c Test3)run()[] int {
c.combo()
return c.all


func(c Test3)combo(){
for i:= 0;我< 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(),\\\


test2:=& Test2 {}
fmt.Println(Test2 final:,test2.run(),\\\


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:[]

游乐场副本: https://play.golang.org/p/upEXINUvNu



任何帮助将不胜感激!


中的所有内容都是按值传递的。

Test3.combo()有值(非指针)接收者:
$ b

  func(c Test3)run()[] int {
c.combo()
返回c.all
}

func(c Test3)combo(){
for i:= 0;我< 2; i ++ {
c.all = append(c.all,i)
fmt.Println(Test3 step,i + 1,c.all)
}
}

这意味着当 Test3.combo()是从> Test3.run(),比如 c.combo(),副本由 c (它的类型是 Test3 )。 组合()方法在副本上运行。它正确地附加了2个数字到 Test3.all ,但是当这个方法返回时,这个副本被放弃。



Test3.run()返回 c.all 时,它返回一个空( nil )切片,因为添加了 Test3.combo()的切片是副本的一个字段,并且已被丢弃。



解决方案:只需使用指针接收器:

  func(c * Test3) combo(){
for i:= 0;我< 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() 返回,更改不会丢失。


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!

解决方案

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.

这篇关于为什么我不能追加到golang中结构属性的切片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆