Home >Backend Development >Golang >Go: Appending second item changes first item

Go: Appending second item changes first item

PHPz
PHPzforward
2024-02-06 11:30:03633browse

Go: Appending second item changes first item

Question content

I don’t know what to say, just look at the code and output. Code:

package main

import (
    "encoding/json"
    "fmt"
)

type Human struct {
    N string `json:"n"`
    C string `json:"c"`
}

func funcname(jDL ...[]byte) {
    jDL_len := len(jDL)
    people := [][]Human{}
    var buf []Human
    var err error
    for i := 0; i < jDL_len; i++ {
        err = json.Unmarshal(jDL[i], &buf)
        fmt.Println("buf", i, buf)
        people = append(people, buf)
        fmt.Println("people", i, people)
    }
    jsoned, err := json.Marshal(people)
    fmt.Println("jsoned", string(jsoned))
    fmt.Println("err", err)
}

func main() {
    i0 := []byte(`[
            {
                "n": "Alice",
                "c": "A1"
            },
            {
                "n": "Bob",
                "c": "A2"
            }
        ]`)
    i1 := []byte(`[
            {
                "n": "Clark",
                "c": "B1"
            },
            {
                "n": "Davis",
                "c": "B2"
            }
        ]`)
    funcname(i0, i1)
}

Output:

buf 0 [{Alice A1} {Bob A2}]
people 0 [[{Alice A1} {Bob A2}]]
buf 1 [{Clark B1} {Davis B2}]
people 1 [[{Clark B1} {Davis B2}] [{Clark B1} {Davis B2}]]
jsoned [[{"n":"Clark","c":"B1"},{"n":"Davis","c":"B2"}],[{"n":"Clark","c":"B1"},{"n":"Davis","c":"B2"}]]
err <nil>

View the people 0 and people 1 strings in the output. I use append to merge buf 0 and buf 1, so the people 1 string in the output should look like this: [[{Alice A1} {Bob A2}]] [{Clark B1} {Davis B2}], i.e. the first element of the array changes to the inserted element, although that shouldn't be the case. What could be the cause and how to fix it?

I didn't try any fixes as I didn't find any issues in the code.


Correct answer


While I agree with others' comments that the fix is ​​to move the buf variable inside the for loop, I also Believe this confusion stems from buf being a slice, and maybe the OP doesn't know how slicing works. Slices are different from arrays, as described in Go Slices: Usage and Internals.

slice

Key sentences quoting the source:

With this in mind, consider the following simplified example:

package main

import "fmt"

func main() {
    slice := [][]int{}
    buf := []int{0} // Slice

    for i := 0; i < 3; i++ {
        // Modifying the slice which is a pointer to an underlying array.
        buf[0] = i
        // Appending the slice (i.e. pointer).
        slice = append(slice, buf)
    }

    fmt.Println(slice)
}

Output: [[2] [2] [2]]

This is the behavior the OP observed in their example. Since slices are pointers to arrays, buf needs to be declared inside the for loop so that each iteration appends a different instance.

Now let's see what happens if we perform the same operation on an array.

Array

Key sentences quoting the source:

Now let's look at an example that demonstrates a copy consisting of the contents of an array when passing it (i.e. when passing it to append):

package main

import "fmt"

func main() {
    slice := [][1]int{}
    buf := [1]int{} // Array

    for i := 0; i < 3; i++ {
        // Modifying the array.
        buf[0] = i
        // Appending a copy of the array.
        slice = append(slice, buf)
    }

    fmt.Println(slice)
}

Output: [[0] [1] [2]]

Now, although the same buf variables are used in the for loop, all the values ​​are different.

The above is the detailed content of Go: Appending second item changes first item. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete