新切片的第一个值为nil

I'm trying to create a simple proof-of-concept for an image resizing server in Golang. I'm new to golang, and am stuck at this frustrating issue. Maybe I haven't understood slices correctly, so please let me where I am wrong in the usage of slices.

I use request.ParseMultipartForm() to parse the files and any POST params sent to the server. Then, I need to convert the list of files (which are a map[string][]*multipart.FileHeader). I'm using the following code to do so.

    // convert the FileHeader map to a list of io.Readers
    images := make([]io.Reader, len(reqForm.File))
    fmt.Println(images)
    for _, fileHeaders := range reqForm.File {
        fh := fileHeaders[0]
        f, err := fh.Open()
        fmt.Printf("Converting: %v
", f)
        if err != nil {
            writeErrorToResponse(resp, err)
            return
        }

        images = append(images, f)
    }

My problem is, for some reason images ends up having a nil as it's first value after being initialized by make. I know this because the fmt.Println(images) (line of code 2) prints out:

[<nil>]

I assumed that the make would return a slice with zero elements. If I do a make([]io.Reader, 0) instead, it works as I expect. I'm confused with this behavior and an explanation would be very helpful.

images := make([]io.Reader, len(reqForm.File)) creates a slice of the given length and the same capacity. When you later append to it, new values are put on the end.

You can fix this in two ways:

  • start with a length 0, but the given capacity with images := make([]io.Reader, 0, len(reqForm.File))
  • start with an empty slice, and allow append to grow it naturally. var images []io.Reader.

I'd choose the latter since it's slightly simpler, and replace it with the preallocated slice later if it turns out it's a bottleneck.

Use an initial length of zero. For example,

images := make([]io.Reader, 0, len(reqForm.File))

The Go Programming Language Specification

Making slices, maps and channels

Call             Type T     Result

make(T, n)       slice      slice of type T with length n and capacity n
make(T, n, m)    slice      slice of type T with length n and capacity m