如何在Golang中的结构中访问切片

How can I access a slice defined inside the struct?

type Car struct {
    Year int
    Name string
    Type []int
}

//Accessing "Type" array field as below causes error: array out of range.

Car.Type[0] = 12
Car.Type[1] = 15
Car.Type[2] = 11

You mistake slice for array. It must be:

type Car struct {
    Year int
    Name string
    Type [3]int // <---
}

See running code

You should read this tour: https://tour.golang.org/moretypes/6

You are confusing Slices and Array. Slices are like dynamic arrays. The way you have defined the slice, their index is not defined until they are appended. For the above code:

type Car struct {
Type []int
}
var car Car
car.Type = append(car.Type, 12)
car.Type = append(car.Type, 15)
car.Type = append(car.Type, 11)

Also, Car in your case is a type of object not a object itself. I have declared object car of type Car.

You can't directly access a slice field if it's not been initialised. You're defining a struct to have 3 fields: Year of type int, this is a simple value that is part of the struct. Same goes for Name. The Type field, however, is a slice. A slice is a reference type. That means it's essentially a hidden struct (called the slice header) with underlying pointer to an array that is allocated dynamically for you. This underlying pointer is, at the time you initialise your variable, nil.

type Car struct {
    Year int
    Name string
    Type []int
}

Can be seen as:

type Car struct {
    Year int
    Name string
    Type struct{
        type: "int",
        array *[]T
    }
}

Not exactly, but you get the idea. When you write:

c := Car{}

All you've allocated is the int, string and the slice header. You must, therefore initialise the slice first:

c := Car{
    Year: 2018,
    Name: "vroom",
    Type: []int{
        1, 2, 3,
    },
}

There are many ways to initialise the slice, of course. You don't have to set the values just yet, but you could, for example, allocate and initialise the memory you need in one go:

c.Type = make([]int, 3) // allocates an initialised 3 elements in the slice to 0

you can also allocate but not initialise the slice by specifying the capacity (this is useful to avoid reallocating and moving the slice around too often):

c.Type = make([]int, 0, 3)

Alternatively, you can have the runtime do it all for you, using append:

c.Type = append(c.Type, 1, 2, 3)

Some examples here


A bit more background. Slices and maps work similarly, broadly speaking. Because they are reference types, that rely on pointers internally, it's possible for functions that have a slice as a return type to return nil for example. This doesn't work for functions returning an int:

func nilSlice() []int {
    return nil
}

Because the return type is a slice, what this function will return is, essentially, an empty slice. Accessing it will result in the same error you occurred: index out of range.

Trying to return nil from a function like this won't even compile:

func nilInt() int {
    nil
}

The resulting error will say something like "Can't use nil as type int". Treat slices as pointer types: they need to be safely initialised before use. Always check their length, and if you need to optimise, look at how the builtin append function is implemented. It'll just exponentially grow the capacity of the underlying array. Something that you may not always want. It's trivial to optimise this sort of stuff