As we know, slicing operations are common in Go programming. However, there're two kinds of slicing expressions:

  • Simple slice expression: a[low : high]
  • Full slice expression: a[low : high : max]

We always see code in the form of the former one. And unfortunatelly in most cases we just forget the latter. We even don't know how to use it.

Firstly, let's check a bug in regexp package of Go, which is fixed by using the full slice expression: ISSUE #30169, CL #161877.

After reading the issue above and figure out how the fixing work. Let's write a much more simple snippet to reproduce the problem:

package main

import (

func noLimitCap(b []byte) []byte {
	return b[1:4] // the simple expression, no limit to the capacity

func limitCap(b []byte) []byte {
	return b[1:4:4] // here we limit the capacity

func testCase(name string, f func([]byte) []byte) {
	fmt.Printf("\n==== case: %s\n", name)
	ob := []byte("abcdefghi")
	p := f(ob)

	fmt.Printf("p = %s (%p)\n", p, p)
	fmt.Printf("ob = %s (%p)\n", ob, ob)

	// Append "..." to the returned subslice
	ap := append(p, []byte("...")...)
	fmt.Printf("ap = %s (%p)\n", ap, ap)
	fmt.Printf("ob = %s (%p)\n", ob, ob)

func main() {
	testCase("noLimitCap", noLimitCap)
	testCase("limitCap", limitCap)


==== case: noLimitCap
p = bcd (0x416031)
ob = abcdefghi (0x416030)
ap = bcd... (0x416031)
ob = abcd...hi (0x416030)

==== case: limitCap
p = bcd (0x416041)
ob = abcdefghi (0x416040)
ap = bcd... (0x416050)
ob = abcdefghi (0x416040)

In limitCap function, with setting the max parameter in a full slice expression, the original byte slice ob was prevented from being mutated by the append operation to its sub slice p.

Therefore, we MUST keep in mind that there's a potential need to use full slice expressions in a function which returns a sub slice.