package main

import (
    "encoding/json"
    "fmt"
)

type AutoGenerated struct {
    Age   int    `json:"age"`
    Name  string `json:"name"`
    Child []int  `json:"child"`
}

func main() {

    jsonStr1 := `{"age": 14,"name": "potter", "child":[1,2,3]}`
    a := AutoGenerated{}
    json.Unmarshal([]byte(jsonStr1), &a)
    aa := a.Child
    fmt.Println(aa) // output:[1,2,3]
    jsonStr2 := `{"age": 12,"name": "potter", "child":[3,4,5,7,8,9]}`
    json.Unmarshal([]byte(jsonStr2), &a)
    fmt.Println(aa) // output: [3,4,5]

    // fmt.Println(a.Child) // output: [3,4,5,7,8,9]
}

解释

type AutoGenerated struct {
  Child []int
}

Then you do

a := AutoGenerated{}                 // (1)

jsonStr1 := `{"age": 14,"name": "potter", "child":[1,2,3]}`
json.Unmarshal([]byte(jsonStr1), &a) // (2)

aa := a.Child                        // (3)
fmt.Println(aa)

jsonStr2 := `{"age": 12,"name": "potter", "child":[3,4,5,7,8,9]}`
json.Unmarshal([]byte(jsonStr2), &a) // (4)

fmt.Println(aa)

So, what happens:

  1. You create a variable, a, of type AutoGenerated which is initialized to the zero value for its type.

    Because of that, its Child field, which is a slice, is initialized to the zero value for a slice which, among other things, means having no backing array.

  2. You unmarshal a JSON document into a, and an array [1, 2, 3] from that documnent got unmarshaled into Child.

    This made the slice allocate a backing array of enough capacity to hold the three element. Please note this.

  3. You copy the slice value from the field Child into the variable aa.

    A slice in Go is a struct of three fields: the capacity, the length and a pointer to (an address of) the backing array holding the slice’s contents. This is what is copied when you copy a slice value. Note that the backing array is not copied; only its address.

  4. You unmarshal another JSON document into a. This time, a longer array gets unmarshaled into the slice in the Child field of a.

    Since it contains twice as much elements Child held before unmarshaling, the code which did the unmarshaling had to reallocate the backing array of the slice: let’s cite the documentation:

    To unmarshal a JSON array into a slice, Unmarshal resets the slice length to zero and then appends each element to the slice. As a special case, to unmarshal an empty JSON array into a slice, Unmarshal replaces the slice with a new empty slice.

    Reallocation made a new fresh backing array and assigned its address to the slice value held in the Child field. Nothing had happened to the slice value in the aa variable: it continued to point to the old backing array.

小结

  1. slice 是个 struct
  2. 仅拷贝了 struct 的 data 字段