Reference Types & Slices

Please help me understand - let me know if I understand this correctly and, if you can, answer my questions. I’m 10 months new to Go and 2 years new to programming.

Slices, Maps, and Channels are reference types. This means they are variables storing an address pointing to some other data structure where the literal values of a primitive / built-in / basic type are stored.

For instance, a slice is “built on-top of” an underlying array. If you have …

xs := []int{2, 3, 7, 8}
fmt.Println(xs)
fmt.Println(len(xs))
fmt.Println(cap(xs))
xs = append(xs, 9)
fmt.Println(len(xs))
fmt.Println(cap(xs))

https://play.golang.org/p/WxVSs4drt1

… then xs is of type []int and that type has a “header” value which stores three things: the address pointing to the underlying array, the length of the slice, and the capacity of the underlying array.

QUESTION #1:
Since a slice is already a reference type, it seems as if I would never pass the value of a slice’s address. Is that correct? When I look at this documentation however …

https://cloud.google.com/appengine/docs/go/datastore/reference#Query.GetAll

… the requested arguments should be of this type:

*[]S or *[]*S or *[]P
also from docs: "... for struct type S or some non- interface, non-pointer type P ..."

QUESTION #2
For one project, I’m working with images.

When I look in the docs at the Image type from package image, I see this:

type Image interface {
// ColorModel returns the Image's color model.
ColorModel() color.Model
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
Bounds() Rectangle
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
At(x, y int) color.Color
}

In my code, I’m opening a bunch of images and storing them in a slice.

var images []image.Image

When I return a value of type []image.Image, the value I am passing is the “address to the underlying array where the images are stored, the length of the slice, and the capacity of the slice” correct? Is the actual image data stored in the underlying array? Also, is there a way to see the parts and sizes of a slice; to actually see the different components which make it up (the addr, the len, the cap) and each of their respective sizes?

Here is all of the code for what I’m working on:

https://github.com/GoesToEleven/la/blob/master/cc/02_image-comparision/02_solution-in-steps/11_abstraction/main.go

Thank you for looking at this, and thank you for responding if you respond!

Best,
Todd

This blog post really helped me understand how slices work. You can think of a slice as a struct defined as:

type sliceHeader struct {
    Length        int
    Capacity      int
    ZerothElement *int
}

So with that lets go to:

QUESTION #1:
Since a slice is already a reference type, it seems as if I would never pass the value of a slice’s address. Is that correct? When I look at this documentation however …

You need to pass the address to a slice in the cases where you change the the sliceHeader (len, cap, or address of backing array) and want that reflected in your calling code. And if you think about it it makes sense. For other types you have to pass a pointer for the caller to be modified.

Take a look at this modified version of your first example: https://play.golang.org/p/NEL3RegcRY

In the case of dontAddNumber, what is passed to that function is a copy of the sliceHeader and any modification to either the len, capacity, or address of the backing array (which append is doing) will not be reflected by xs in main.

Also check out the path example from the blog post above for a better explanation.

1 Like

I’d recommend taking a read through this blog post: http://blog.golang.org/go-slices-usage-and-internals

The len and cap functions will tell you the length & capacity of the slice. I’m not sure how to get the pointer to the underlying array storage, though (maybe with reflect?).

Re: []image.Image - you’re mostly right in your description, the slice holds a pointer to the inside of the array storage, where the slice starts. (Slices are allowed to start part-ways through an array).

The underlying array will hold the image.Images, which have the following implementation: https://golang.org/src/image/image.go#L60 - note that the pixel data is held in yet another slice.

So if you say images[7].(*RGBA).Pix[103], you’re going to be following a series of pointers to retrieve that data. One hop to the address images.ptr+7*sizeof(image.Image), another hop to the address of RGBA (because it’s a pointer), and a final hop to address Pix.ptr + 103. (I may be ignoring some cost of the type assertion to *RGBA here).

Luckily, it’s all pretty transparent to us programmers - we just say what we want and the computer retrieves it for us.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.