Array and Slices
Table of Contents
- Basics of
[N]T
(arrays) - Basics of
[]T
(slices) - How
append()
works - Test the equality of two slices
- Passing slices by value vs by pointer?
- Iterate in reverse order
- Slice Tricks
- Convert slice of strings to slice of int
- Transform
[]int
tostring
with one line
Basics of [N]T
(arrays) tutorial
- A fixed-length sequence of zero or more elements of a particular type.
- Arrays are copied when passing them as arguments.
var q [3]int = [3]int{1, 2, 3}
var r [3]int = [3]int{1, 2}
// if an “...” appears in place of the length, the length is determined by the initializers.
// The size must be a constant expression,
q := [...]int{1, 2, 3}
const (
USD Currency = iota
EUR
GBP
RMB
)
// Init with Index, value pairs.
// The pairs can appear in any order
symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}
// Some can be omitted (defines [0, 0, ..., -1])
r := [...]int{99: -1}
- http://www.gopl.io/ (4.1)
Basics of []T
(slices) tutorial
- A slice type is written
[]T
- A slice has three components: a
pointer
, alength
, and acapacity
. - The
pointer
points to the first element of the array that is reachable through the slice - The
length
is the number of slice elements - The
capacity
is usually the number of elements between the start of the slice and the end of the underlying array. - Copying a slice creates an alias for the underlying array.
- Unlike arrays, slices are not comparable.
- The only legal slice comparison is against
nil
. - A
nil
slice behaves like any other zero-length slice
If you need to test whether a slice is empty, use
len(s) == 0
, not s == nil
.
package main
import "fmt"
func reverse(s []int) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
func main() {
a := [...]int{0, 1, 2, 3, 4, 5}
reverse(a[:]) // modifies `a`
fmt.Println(a)
}
[5 4 3 2 1 0]
- The slice operator
s[i:j]
- Creates a new slice that refers to elements
i
throughj-1
of the sequences
, - When omitted,
i
is0
, andj
islen(s)
. 0 ≤ i ≤ j ≤ cap(s)
- Slicing beyond
cap(s)
causes a panic - Slicing beyond
len(s)
extends the slice, so the result may be longer than the original
- Creates a new slice that refers to elements
How append()
works discussion
func appendInt(x []int, y int) []int {
var z []int
zlen := len(x) + 1
if zlen <= cap(x) {
// There is room to grow. Extend the slice.
z = x[:zlen]
} else {
// There is insufficient space. Allocate a new array.
// Grow by doubling, for amortized linear complexity.
zcap := zlen
if zcap < 2*len(x) {
zcap = 2 * len(x)
}
z = make([]int, zlen, zcap)
copy(z, x)
}
z[len(x)] = y
return z
}
As we cannot know when
append()
grows the underlying array, we can’t assume that the original slice refers to the same array as the resulting slice, nor that it refers to a different one.
a := [...]int{0, 1, 2, 3}
b := a[1:2]
fmt.Println(b)
c := append(b, 99)
fmt.Println(c)
// a is affected by `append()` on `b`
fmt.Println(a)
[1]
[1 99]
[0 1 99 3]
Test the equality of two slices howto
func isEqual(a, b []int) bool {
if (a == nil) != (b == nil) {
return false
}
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
Passing slices by value vs by pointer? discussion
It’s idiomatic to have functions like slice = doSomethingWithSlice(slice) and
less
so to seedoSomethingWithSlice(&slice)
Iterate in reverse order howto
1 2 3 4 5
Slice Tricks howto
Convert slice of strings to slice of int howto
- There is no concise way to do it:
import "strconv"
func sliceAtoi(sa []string) ([]int, error) {
si := make([]int, 0, len(sa))
for _, a := range sa {
i, err := strconv.Atoi(a)
if err != nil {
return si, err
}
si = append(si, i)
}
return si, nil
}
Transform []int
to string
with one line howto
1 2 3