Go: Common mistakes: Confusing Arrays with Slices

Having recently browsed stackoverflaw I've noticed quite a few question where people end up confusing arrays with slices. How do we tell arrays apart from slices? If there's a number between [] it's an array, otherwise it's a slice.

[]T      // this is a slice
[]byte   // also a slice
[5]T     // not a slice
[1]byte  // also not a slice
[N]T     // again, not a slice

I like to think of a slice as a pointer to a segment of an array. Arrays are values, slices are pointers:

func a(data [1]byte) {
	data[0] = 1
}

func b(data []byte) {
	data[0] = 1
}

func main() {
	var arr [1]byte = [1]byte{0}
	var slc []byte = []byte{0}

	a(arr)
	fmt.Println(arr) // prints [0]

	b(slc)
	fmt.Println(slc) // prints [1]
}


More than that... since arrays and slices are completely different things you can't assign a []T to a [n]T and neither can you assign [n]T to []T:

func main() {
	var arr [1]byte = [1]byte{0}
	var slc []byte = []byte{0}

	a(slc)			// illegal
	fmt.Println(slc)

	b(arr)			// illegal
	fmt.Println(arr)
}

How do we convert an array to a slice? Well... we can't really "convert" an array to a slice but we can get a slice that points to our array by using [:]:

func main() {
	var arr [1]byte = [1]byte{0}
	var slc []byte = []byte{0}

	a(slc[:])		// NO! still illegal
	fmt.Println(slc)

	b(arr[:])		// legal
	fmt.Println(arr)
}

But... how do we convert a slice to an array? We can do it with reflect trickery which I won't show you how to. Instead, we can always create an array and use copy but we need to know the length in advance:

func main() {
	var arr [1]byte = [1]byte{0}
	var slc []byte = []byte{0}

	var temp [1]byte
	copy(temp[:], slc)
	a(temp)			// legal
	fmt.Println(temp)	// ... but obviously still prints [0]

	b(arr[:])		// legal
	fmt.Println(arr)
}

However, if you do this, I'd advise to check the length of the slice first to ensure that it has the exact size you want (otherwise you may copy less than you'd expect)