Representation

Slices are represented by a runtime.slice struct (slice header):

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}
  • array is a pointer to the underlying array
  • len represents the length of a slice
  • cap indicates the capacity of a slice

Note that, slice is not a pointer to a struct

nil Slice

nil slice is actually a zero value of the slice header:

slice {
	array: nil,
	len:   0,
	cap:   0,
}

Empty Slice

Empty slice is just a slice with len and cap equal to 0 and array pointing to zero-sized array:

slice {
	array: unsafe.Pointer(&zerobase),
	len:   0,
	cap:   0,
}

The value of the array is the address of the runtime.zerobase, the base address for all 0-byte allocations

Grow Factor

The slices grow as follows:

const threshold = 256
if cap < threshold {
	cap = cap*2
} else {
	cap = cap + (cap + 3*threshold) / 4
}

So, the growth factor is roughly 2x for small slices and 1.25x for large slices, plus a constant for a smoother transition.

Type Information

Type information about the slice data type is represented by an abi.SliceType struct:

type SliceType struct {
	Type
	Elem *Type // slice element type
}

Invariance and Conversions

Slices are invariant. This is one of the reasons why we can’t convert []T to an []interface{}
Another, is that memory layout of these two slices is different:

  • Each interface{} takes up two words. As a consequence, a slice with length N and with type []interface{} is backed by a chunk of data that is N*2 words long
  • This is different than the chunk of data backing a slice with type []MyType and the same length. Its chunk of data will be N*sizeof(MyType) words long

  • Converting a slice to an array yields an array containing the elements of the underlying array of the slice
  • Converting a slice to an array pointer yields a pointer to the underlying array of the slice

In both cases, if the length of the slice is less than the length of the array, a panic occurs

Note that converting a nil slice to an array pointer yields a nil pointer, while converting an empty slice to an array pointer yields a non-nil pointer

References