# Three-Index Slices in Go 1.2

- Published: December 17, 2013
- Author: William Kennedy
- URL: https://www.ardanlabs.com/blog/2013/12/three-index-slices-in-go-12.html

With the release of Go 1.2, slices gained the ability to specify the capacity when performing a slicing operation. This doesn't mean we can use this index to extend the capacity of the underlying array. It means we can create a new slice whose capacity is restricted. Restricting the capacity provides a level of protection to the underlying array and gives us more control over append operations.<br />
<br />

Here are the release notes and design document for the feature request:<br />
<br />
<a href="http://tip.golang.org/doc/go1.2#three_index" target="_blank"><span class="sr-only">External resource on tip.golang.org: </span>http&#58;//tip.golang.org/doc/go1.2#three_index</a><br />
<a href="https://docs.google.com/document/d/1GKKdiGYAghXRxC2BFrSEbHBZZgAGKQ-yXK-hRKBo0Kk/pub" target="_blank"><span class="sr-only">External resource on docs.google.com: </span>https&#58;//docs.google.com/document/d/1GKKdiGYAghXRxC2BFrSEbHBZZgAGKQ-yXK-hRKBo0Kk/pub</a><br />
<br />
Let's write some code to explore using the new capacity index. As with all my slice posts, I am going to use this InspectSlice function:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
func InspectSlice(slice []string) {<br />
&nbsp; &nbsp; // Capture the address to the slice structure<br />
&nbsp; &nbsp; address := unsafe.Pointer(&amp;slice)<br />
<br />
&nbsp; &nbsp; // Capture the address where the length and cap size is stored<br />
&nbsp; &nbsp; lenAddr := uintptr(address) + uintptr(8)<br />
&nbsp; &nbsp; capAddr := uintptr(address) + uintptr(16)<br />
<br />
&nbsp; &nbsp; // Create pointers to the length and cap size<br />
&nbsp; &nbsp; lenPtr := (&#42;int)(unsafe.Pointer(lenAddr))<br />
&nbsp; &nbsp; capPtr := (&#42;int)(unsafe.Pointer(capAddr))<br />
<br />
&nbsp; &nbsp; // Create a pointer to the underlying array<br />
&nbsp; &nbsp; addPtr := (&#42;[8]string)(unsafe.Pointer(&#42;(&#42;uintptr)(address)))<br />
<br />
&nbsp; &nbsp; fmt.Printf(&quot;Slice Addr[%p] Len Addr[0x%x] Cap Addr[0x%x]\n&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; address,<br />
&nbsp; &nbsp; &nbsp; &nbsp; lenAddr,<br />
&nbsp; &nbsp; &nbsp; &nbsp; capAddr)<br />
<br />
&nbsp; &nbsp; fmt.Printf(&quot;Slice Length[%d] Cap[%d]\n&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &#42;lenPtr,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &#42;capPtr)<br />
<br />
&nbsp; &nbsp; for index := 0; index &lt; &#42;lenPtr; index++ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;[%d] %p %s\n&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp;(&#42;addPtr)[index],<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (&#42;addPtr)[index])<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; fmt.Printf(&quot;\n\n&quot;)<br />
}
</div>
<br />
To start, let's create a slice we will use as our source:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
source := []string{&quot;Apple&quot;, &quot;Orange&quot;, &quot;Plum&quot;, &quot;Banana&quot;, &quot;Grape&quot;}<br />
InspectSlice(source)<br />
<br />
<br />
Output:<br />
Slice Addr[0x210231000] Len Addr[0x210231008] Cap Addr[0x210231010]<br />
Slice Length[5] Cap[5]<br />
[0] 0x21020e140 Apple<br />
[1] 0x21020e150 Orange<br />
<b>[2] 0x21020e160 Plum</b><br />
[3] 0x21020e170 Banana<br />
[4] 0x21020e180 Grape
</div>
<br />
We start with a slice of strings with a length and capacity of 5. This means the underlying array has 5 elements and we have access to the entire array.<br />
<br />
Next, let's take a traditional slice of the <i><b>source</b></i> and inspect the contents:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
takeOne := source[2:3]<br />
InspectSlice(takeOne)<br />
<br />
<br />
Output:<br />
Slice Addr[0x210231040] Len Addr[0x210231048] Cap Addr[0x210231050]<br />
Slice Length[1] Cap[3]<br />
<b>[0] 0x21020e160 Plum
</b></div>
<br />
With this slice operation we only take the third element from the <i><b>source</b></i>. You can see the first element of the <i><b>takeOne</b></i> slice has the same address as the third element of the <i><b>source</b></i> slice. The <i><b>takeOne</b></i>&nbsp;slice has a length of one and a capacity of three. This is because there are three elements left in the underlying array that are available for use.<br />
<br />
What if we didn't want the new slice to have access to the remaining capacity? Prior to version 1.2, this was not possible. Let's take the slice again, but this time restrict the capacity to one:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
takeOneCapOne := source[2:3:3] &nbsp;// Use the third index position to<br />
InspectSlice(takeOneCapOne) &nbsp; &nbsp; // set the capacity<br />
<br />
<br />
Output:<br />
Slice Addr[0x210231060] Len Addr[0x210231068] Cap Addr[0x210231070]<br />
Slice Length[1] Cap[1]<br />
[0] 0x21020e160 Plum
</div>
<br />
After creating the <i><b>takeOneCapOne</b></i> slice, the length and capacity are now one. The&nbsp;<i><b>takeOneCapOne</b></i>&nbsp;slice no longer has access to the remaining capacity in the underlying array.<br />
<br />
Length and capacity is calculated using this formula:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
For slice[ i : j : k ] the<br />
<br />
Length: &nbsp; j - i<br />
Capacity: k - i
</div>
<br />
If we attempt to set the capacity greater than the underlying array, the code will panic.<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
takeOneCapFour := source[2:3:6] &nbsp;// (6 - 2) attempts to set the capacity<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// to 4. This is greater than what is<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// available.<br />
<br />
Runtime Error:<br />
panic: runtime error: slice bounds out of range<br />
<br />
goroutine 1 [running]:<br />
runtime.panic(0x9ad20, 0x1649ea)<br />
&nbsp; &nbsp; /Users/bill/go/src/pkg/runtime/panic.c:266 +0xb6<br />
main.main()<br />
&nbsp; &nbsp; /Users/bill/Spaces/Test/src/test/main.go:15 +0x24f</div>
<br />
So what happens if we append an element to the&nbsp;<i><b>takeOneCapOne</b></i>&nbsp;slice?<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
source := []string{&quot;Apple&quot;, &quot;Orange&quot;, &quot;Plum&quot;, &quot;Banana&quot;, &quot;Grape&quot;}<br />
InspectSlice(source)<br />
<br />
takeOneCapOne := source[2:3:3]<br />
InspectSlice(takeOneCapOne)<br />
<br />
takeOneCapOne = append(takeOneCapOne, &quot;Kiwi&quot;)<br />
InspectSlice(takeOneCapOne)
</div>
<br />
Here is the output:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
Slice Addr[0x210231000] Len Addr[0x210231008] Cap Addr[0x210231010]<br />
Slice Length[5] Cap[5]<br />
[0] 0x21020e140 Apple<br />
[1] 0x21020e150 Orange<br />
<b>[2] 0x21020e160 Plum</b><br />
[3] 0x21020e170 Banana<br />
[4] 0x21020e180 Grape<br />
<br />
-- Before Append --<br />
<br />
Slice Addr[0x210231040] Len Addr[0x210231048] Cap Addr[0x210231050]<br />
Slice Length[1] Cap[1]<br />
<b>[0] 0x21020e160 Plum</b><br />
<br />
-- After Append --<br />
<br />
Slice Addr[0x210231080] Len Addr[0x210231088] Cap Addr[0x210231090]<br />
Slice Length[2] Cap[2]<br />
<b>[0] 0x210231060 Plum</b><br />
[1] 0x210231070 Kiwi
</div>
<br />
When we append an element to the&nbsp;<i><b>takeOneCapOne</b></i>&nbsp;slice, a new underlying array is created for the slice. This new underlying array contains a copy of the elements being referenced from the <i><b>source</b></i> and then is extended to add the new element. This is because the capacity of the&nbsp;<i><b>takeOneCapOne</b></i>&nbsp;slice was reached and append needed to grow the capacity. Notice how the address changes in the&nbsp;<i><b>takeOneCapOne</b></i>&nbsp;slice after the append.<br />
<br />
How is this different from not setting the capacity?<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
source := []string{&quot;Apple&quot;, &quot;Orange&quot;, &quot;Plum&quot;, &quot;Banana&quot;, &quot;Grape&quot;}<br />
InspectSlice(source)<br />
<br />
<b>takeOne := source[2:3] &nbsp;// Don't specify capacity</b><br />
InspectSlice(takeOne)<br />
<br />
takeOne = append(takeOne, &quot;Kiwi&quot;)<br />
InspectSlice(takeOne)<br />
<br />
InspectSlice(source)</div>
<br />
Here is the output:<br />
<br />
<div style="background-color: #efefef; font-family: 'Courier New', Courier, monospace; font-size: small; overflow-x: scroll; padding: 10px; white-space: nowrap;">
Slice Addr[0x210231000] Len Addr[0x210231008] Cap Addr[0x210231010]<br />
Slice Length[5] Cap[5]<br />
[0] 0x21020e140 Apple<br />
[1] 0x21020e150 Orange<br />
<b>[2] 0x21020e160 Plum</b><br />
<b>[3] 0x21020e170 Banana</b><br />
[4] 0x21020e180 Grape<br />
<br />
-- Before Append --<br />
<br />
Slice Addr[0x210231040] Len Addr[0x210231048] Cap Addr[0x210231050]<br />
Slice Length[1] Cap[3]<br />
<b>[0] 0x21020e160 Plum</b><br />
<br />
-- After Append --<br />
<br />
Slice Addr[0x210231060] Len Addr[0x210231068] Cap Addr[0x210231070]<br />
Slice Length[2] Cap[3]<br />
<b>[0] 0x21020e160 Plum</b><br />
<b>[1] 0x21020e170 Kiwi</b><br />
<br />
<br />
Slice Addr[0x210231080] Len Addr[0x210231088] Cap Addr[0x210231090]<br />
Slice Length[5] Cap[5]<br />
[0] 0x21020e140 Apple<br />
[1] 0x21020e150 Orange<br />
<b>[2] 0x21020e160 Plum</b><br />
<b>[3] 0x21020e170 Kiwi</b><br />
[4] 0x21020e180 Grape
</div>
<br />
This time the append uses the existing capacity and overwrites the value at element 4 in the underlying array. This could be a disaster if this was not our intent.<br />
<br />
This new feature of setting the capacity can really help protect us and our data from unwanted overwrites. The more we can leverage the built-in functions and runtime to handle these types of operations the better. These types of bugs are very difficult to find so this is going to help immeasurably.<br />
<br />
Here are other posts about slices:<br />
<br />
<a href="https://www.ardanlabs.com/blog/2013/08/understanding-slices-in-go-programming.html" target="_blank">Understanding Slices In Go Programming</a><br />
<a href="https://www.ardanlabs.com/blog/2013/08/collections-of-unknown-length-in-go.html" target="_blank">Collections Of Unknown Length In Go</a><br />
<a href="https://www.ardanlabs.com/blog/2013/09/slices-of-slices-of-slices-in-go.html" target="_blank">Slices Of Slices Of Slices In Go</a><br />
<a href="https://www.ardanlabs.com/blog/2013/09/iterating-over-slices-in-go.html" target="_blank">Iterating Over Slices In Go</a><br />
<br />
