Slice is a scalable collection type, unlike Array.
Slice has advantages over Array in terms of memory usage and speed.
Slice Declaration
var slice []string
slice = make([]string, 3)
slice[0] = "hello"
slice[2] = "hi"
fmt.Println(slice[0], slice[1], slice[2])
// hello hi
numSlice := make([]int, 3)
numSlice[0] = 1
numSlice[1] = 2
numSlice[2] = 3
fmt.Println(numSlice[0], numSlice[1], numSlice[2])
// 1 2 3
There are two ways to declare Slices.
make function makes a Slice.
Zero Initialization
Like Array, Slice elements that do not assign any value are returned with zero values.
intSlice := make([]int, 3)
strSlice := make([]string, 3)
boolSlice := make([]bool, 3)
fmt.Println(intSlice, strSlice, boolSlice)
// [0 0 0] [ ] [false false false]
However, slice variables that are not assigned any slices have nil values.
var intSlice []int
var strSlice []string
var boolSlice []bool
fmt.Printf("%#v, %#v, %#v\n", intSlice, strSlice, boolSlice)
// []int(nil), []string(nil), []bool(nil)
Slice Literal
fruits := []string{"apple", "banana", "cherry"}
fmt.Println(fruits)
// [apple banana cherry]
With slice literal, you do not need to use the make function because it automatically generates Slice and set values.
Slice with Loop
It is the same as Array.
numSlice := []int{3, 6, 9}
for i := 0; i < len(numSlice); i++ {
fmt.Println(i, numSlice[i])
}
// 0 3
// 1 6
// 2 9
for index, value := range numSlice {
fmt.Println(index, value)
}
// 0 3
// 1 6
// 2 9
Slice Operator
All Slices are implemented based on the underlying Array.
The slice operator (slicing) allows you to create a Slice based on an Array.
numArray := [5]int{1, 2, 3, 4, 5}
// +---+---+---+---+---+
// index | 0 | 1 | 2 | 3 | 4 |
// +---+===+===+===+---+
// value | 1 | 2 | 3 | 4 | 5 |
// +---+===+===+===+---+
numSlice := numArray[1:4]
fmt.Print(numSlice)
// [2 3 4]
[1:4] means getting elements from the 1st index of the Array to the 3rd (before 4th) index of the Array.
numArray := [5]int{1, 2, 3, 4, 5}
numSlice := numArray[:3]
fmt.Print(numSlice)
// [1 2 3]
numSlice = numArray[3:]
fmt.Print(numSlice)
// [4 5]
If you omit the starting index, it uses 0 by default.
If you omit the ending index, it uses the last index + 1 by default.
numArray := [5]int{1, 2, 3, 4, 5}
numSlice1 := numArray[:3]
fmt.Println(numSlice1)
// [1 2 3]
numSlice2 := numArray[2:]
fmt.Println(numSlice2)
// [3 4 5]
Multiple Slices can point to the same underlying Array.
numArray := [5]int{1, 2, 3, 4, 5}
numSlice := numArray[:3]
fmt.Println(numSlice)
// [1 2 3]
numArray[1] = 6
fmt.Println(numSlice)
// [1 6 3]
numSlice[2] = 7
fmt.Println(numArray)
// [1 6 7 4 5]
If you change the value of the underlying Array, the value of the Slice also changes accordingly, and vice versa.
Because of these potential problems, it is generally better to create Slices using make() or slice literal than to create Array first and use slice operators.
This is because if you use make() or slice literal, you don't need to touch the underlying Array.
Adding Elements to Slice
fruits := []string{"apple", "banana"}
fmt.Println(fruits)
// [apple banana]
fruits = append(fruits, "cherry")
fmt.Println(fruits)
// [apple banana cherry]
fruits = append(fruits, "durian", "eggfruit")
fmt.Println(fruits)
// [apple banana cherry durian eggfruit]
append function returns a new Slice with new elements.
You can append a single element, even multiple elements.
The returned Slice shares an underlying array with the original Slice.
slice1 := []int{1, 2, 3}
slice2 := append(slice1, 4)
slice3 := append(slice2, 5)
slice3[0] = 9
fmt.Println(slice2)
// [9 2 3 4]
fmt.Println(slice3)
// [9 2 3 4 5]
Therefore, reassigning the same variable is necessary to avoid this problem.
Sorting Elements in Slice
slice := []int{3, 5, 4, 2, 1}
sort.Ints(slice)
fmt.Println(slice)
// [1 2 3 4 5]
sort package provides sorting methods of fundamental types.
If you provide Len(), Less(), Swap() functions, you can sort your own type, such as structure.
package main
import (
"fmt"
"sort"
)
type person struct {
name string
age int
}
type persons []person
func (p persons) Len() int {
return len(p)
}
func (p persons) Less(i, j int) bool {
return p[i].age < p[j].age
}
func (p persons) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
func main() {
p := persons{
{"kim", 31},
{"lee", 18},
{"park", 23},
}
sort.Sort(persons(p))
fmt.Println(p)
// [{lee 18} {park 23} {kim 31}]
}
Structure of Slice
Slice is saved internally like the following structure.
type SliceHeader struct {
Data uintptr // Pointer to array
Len int // Number of elements
Cap int // Length of array
}
For example, let's assume this array.
[ 0 | 1 | 2 | - | - ]
In this case, Len is 3 and Cap is 5.
slice := make([]int, 3, 5)
slice[0] = 0
slice[1] = 1
slice[2] = 2
fmt.Println(slice, len(slice), cap(slice))
// [0 1 2] 3 5
And, you should focus on the pointer.
It makes a difference from an array.
'Go' 카테고리의 다른 글
[Go] Interface (0) | 2021.10.17 |
---|---|
[Go] Method (0) | 2021.10.17 |
[Go] Package (0) | 2021.10.16 |
[Go] Rune and String (0) | 2021.10.16 |
[Go] Pointer (0) | 2021.10.11 |
댓글