# 21. Slices

### Slice Type

Array size is fixed in Go. We can not add more elements to an existing array. This is limiting from a programmer's point of view. Go provides slices to address this concern.

Slices in Go can grow. Arrays are fixed length sequence where as slices are variable length sequence in Go. Slices are very lightweight data structures.A slice has three components: a pointer, a length, and a capacity.&#x20;

### Declaring slice

While declaring slice, we need to specify type of element slice will hold with empty pair of `[]`.

&#x20;`[]T` defines a slice of type T.

{% code title="main.go" %}

```go
func printSlice(s []string) {
	fmt.Printf("size: %v, capacity:%v,value:%v\n",
		len(s), cap(s), s)
}
func main() {
	// declaring slice
	var names []string
	printSlice(names)
	//output size: 0, capacity:0,value:[]
}
```

{% endcode %}

While declaring an array, we need to specify size while slice declaration has empty size. `a` is an array below while `s` is a slice.

{% code title="main.go" %}

```go
var a [5]int
var s []int
```

{% endcode %}

### Creating slice

Declaring slice using var does not allocate backing array for slice. Instead, we have to create slice using `make` function. Make function accepts 3 parameters, first is type of slice, second is length of slice to create and optionally third parameter as capacity of slice.

`s := make([]T,length,capacity)`&#x20;

{% code title="main.go" %}

```go
names = make([]string, 5)
printSlice(names)
// output : size: 5, capacity:5, value:[    ]
```

{% endcode %}

If we know in advance, what capacity we need for slice, we can make slice with that capacity.

{% code title="main.go" %}

```go
names = make([]string, 5, 20)
printSlice(names)
// output : size: 5, capacity:20, value:[    ]
```

{% endcode %}

### Accessing slice elements

Since slice is window into an array, its elements can be accessed by using square brackets `[]` with an index that begins at `0` similar to array access.

{% code title="main.go" %}

```go
greetings := make([]string, 2)
greetings[0] = "Hello"
greetings[1] = "World"
printSlice(greetings)
// output: size: 2, capacity:2, value:[Hello World]
```

{% endcode %}

### Zero values

When new slice is created using `make` all its elements get initialized to its zero values.

{% code title="main.go" %}

```go
numbers := make([]float64, 8)
months := make([]string, 12)
fmt.Println(numbers)
fmt.Println(months)
// output : 
// numbers => [0 0 0 0 0 0 0 0]
// months => [           ]
```

{% endcode %}

### Slice literals

If  we know in advance what values a slice will start with, we can initialize the slice with those values using slice literal. We do not need to  `make` function call when using slice literals.

`[]T{values}`

{% code title="main.go" %}

```go
data := []string{
		"Hello",
		"World!",
	}
printSlice(data)
//out size: 2, capacity:2, value:[Hello World!]
```

{% endcode %}

### Slice from an existing array

We can create slice from an existing array. To create slice from existing array, we need to specify start index and end index using syntax `array[startIndex:endIndex]`

If starting index is zero, it can be skipped. If end index equals length of array, it can be skipped.

{% code title="main.go" %}

```go
days := [7]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
	weekdays := days[0:5]
	// if first element of slice is same as first 
	//element of array, start index can be skipped
	weekdays = days[:5]
	printSlice(weekdays)

	weekend := days[5:7]
	// if last element of slice is same as last 
	// element of array, end index can be skipped
	weekend = days[5:]
	printSlice(weekend)

	alldays := days[0:7]
	// if slice has all array elements, both start 
	// index and end index can be skipped
	alldays = days[:]
	printSlice(alldays)
```

{% endcode %}

### Nil and empty slice

Go has both nil and empty slices. When we use var declaration, it initializes nil slice provided we do not use slice literal. If we use short variable declaration and create slice using make, it initializes empty slice. In case of nil slice, no backing array is created, while for empty slice backing array is present.

{% hint style="success" %}
use `len(s) == 0`, and not `s == nil`for checking for empty slice.
{% endhint %}

{% code title="main.go" %}

```go
// empty and nil slices
s := make([]string, 3)[3:]
var e []string
printSlice(s)
printSlice(e)

fmt.Println("Is s nil => ", s == nil)
fmt.Println("Is e nil => ", e == nil)
```

{% endcode %}

### Iterating over slice

Iteration over slice is similar to array iteration. Preferred way is to `for...range`

{% code title="main.go" %}

```go
// iterating over slices
for _, day := range alldays {
	fmt.Println(day)
}
```

{% endcode %}

### Type of slice and comparison

Unlike array, slice types are defined what type of data slice store. Comparison is not possible using `==` unlike arrays. For most use cases where comparison needs to be done, we need to write our own comparison code

{% code title="main.go" %}

```go
func testEquality(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
```

{% endcode %}

### Append

The advantage slices have over arrays is the fact that slices can increase capacity and hold more elements at run-time. To add elements to slice, we use built in `append` function.

`append` can be used to add one or more elements to slice. Append operation may create new slice if new elements to add do not fit in existing capacity of slice.&#x20;

{% hint style="success" %}
Whenever we do append operation, we reassigned the returned slice to original slice. Returned slice may or may not be new slice.
{% endhint %}

`s := append(s, e)`

{% code title="main.go" %}

```go
s := make([]string, 0)
// appending elements
s = append(s, "a")
printSlice(s)
s = append(s, "e")
printSlice(s)
s = append(s, "i")
printSlice(s)
s = append(s, "o")
s = append(s, "u")
printSlice(s)
// output
// size: 1, capacity:1, value:[a]
// size: 2, capacity:2, value:[a e]
// size: 3, capacity:4, value:[a e i]
// size: 5, capacity:8, value:[a e i o u]
```

{% endcode %}

### GitHub Code

{% embed url="<https://github.com/gophersumit/codewithgo-samples/blob/master/slices/main.go>" %}

{% embed url="<https://github.com/quii/learn-go-with-tests/blob/master/arrays-and-slices.md>" %}

### Blog Posts

{% embed url="<https://blog.golang.org/go-slices-usage-and-internals>" %}

{% embed url="<https://www.ardanlabs.com/blog/2013/08/understanding-slices-in-go-programming.html>" %}

{% embed url="<https://www.ardanlabs.com/blog/2013/09/slices-of-slices-of-slices-in-go.html>" %}

{% embed url="<https://www.ardanlabs.com/blog/2013/09/iterating-over-slices-in-go.html>" %}

{% embed url="<https://github.com/golang/go/wiki/SliceTricks>" %}

### Videos

{% embed url="<https://www.youtube.com/watch?v=fhdA-6LcOxk>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.codewithgo.com/slices.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
