Go container: Array, Slice, Map

1, Array array

Go language array is a fixed length sequence, and its internal elements generally limit the same type. The array is the underlying structure of the slice.

//Create array 1: assignment after declaration
var arr1 [3]int
arr1[0] = 0
arr1[1] = 1
arr1[2] = 2
    
//Create array 2: create and initialize
arr2 := [3]int{1, 3, 5}
    
//Create array 3: automatically calculate array length
arr3 := [...]int{2, 4, 6, 8, 10}
    
//len() is a built-in function used to obtain the length of arrays, slices, strings, channel s, etc
var count = len(arr3)
fmt.Printf("Type is%T,Value is%v,The number of elements is%d\n", arr3, arr3, count)
//The type is [6]int, the value is [1 2 3 4 5 6], and the number of elements is 6

//Declare a two-dimensional array of two rows and three columns
var grid [2][3]int
grid[0] = [3]int{1,3,5}
grid[1] = [3]int{2,4,6}
fmt.Println(grid)    //[[1 3 5] [2 4 6]]
  
    


//Traversal array
for index, value := range arr1 {
    fmt.Println(index, " ", value)
}
//0   0
//1   1
//2   2
//3   3
//4   4

2, Slice slice

1. Slice declaration and initialization
//array[start:end] intercepts a fragment with the subscript [start,end) from the array to form a slice
//Start stands for the start subscript. If not written, the default stands for cutting from scratch
//End stands for the end subscript (not included in itself). If it is not written, it will be intercepted to the end by default
func BaseSlice01() {
    //Declare and initialize an array
    var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    
    //Create slices based on arrays
    slice1 := arr[2:5]
    slice2 := arr[:5]
    slice3 := arr[6:]
    slice4 := arr[:]

    fmt.Printf("arr Type is%T,Value is%v\n", arr, arr)  //The arr type is [8]int and the value is [0 1 2 3 4 5 6 7]  
    fmt.Printf("slice1 Type is%T,Value is%v\n", slice1, slice1)   //slice1 type is [] int, value is [2 3 4]
    fmt.Printf("slice2 Type is%T,Value is%v\n", slice2, slice2)  //slice2 type is [] int, value is [0 1 2 3 4]
    fmt.Printf("slice3 Type is%T,Value is%v\n", slice3, slice3)  //slice3 type is [] int and value is [6 7]
    fmt.Printf("slice4 Type is%T,Value is%v\n", slice4, slice4)  //slice4 type is [] int, value is [0 1 2 3 4 5 6 7]

}
2. Slice additional elements
//Append element to slice
func BaseSlice02() {
    slice := []int{1, 2, 3, 4}
    slice = append(slice, 5, 6) //Append multiple elements directly
    slice = append(slice, []int{7, 8, 9}...) //To add an element in another slice, you need to "flatten" the added element, followed by that will do
    fmt.Printf("slice1 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice, slice, len(slice), cap(slice))
    slice1 Type is[]int,Value is[1 2 3 4 5 6 7 8 9],Length 9,Capacity 16

    //Traversal slice
    for _, v := range slice {
        fmt.Print(v, " ")
    }
    //1 2 3 4 5 6 7 8 9 
}
3. Slice capacity expansion
//cap(slice) obtains the capacity of the slice
//At the beginning of creation, the capacity is equal to the length
//When expanding, once the capacity cannot meet the needs, it will be expanded by doubling the capacity
//Pay attention to the change of stack address during slice expansion
func BaseSlice03() {
    arr := [4]int{1, 2, 3, 4}
    fmt.Printf("arr Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", arr, arr, len(arr), cap(arr), &arr)

    slice := arr[:]
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)

    slice = append(slice, 5)
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)
    slice = append(slice, 6)
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)
    slice = append(slice, 7)
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)
    slice = append(slice, 8)
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)
    slice = append(slice, 9)
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)
    slice = append(slice, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
    fmt.Printf("slice Type is%T,Value is%v,Count Reg%d,Capacity%d,Address is%p\n", slice, slice, len(slice), cap(slice), slice)
}

//The arr type is [4]int, the value is [1 2 3 4], the length is 4, the capacity is 4, and the address is 0xc00011e000
//slice type is [] int, value is [1 2 3 4], length is 4, capacity is 4, and address is 0xc00011e000
//slice type is [] int, value is [1 2 3 4 5], length is 5, capacity is 8, and address is 0xc000126040
//slice type is [] int, value is [1 2 3 4 5 6], length is 6, capacity is 8, and address is 0xc000126040
//slice type is [] int, value is [1 2 3 4 5 6 7], length is 7, capacity is 8, and address is 0xc000126040
//slice type is [] int, value is [1 2 3 4 5 6 7 8], length is 8, capacity is 8, and address is 0xc000126040
//slice type is [] int, value is [1 2 3 4 5 6 7 8 9], length is 9, capacity is 16, and address is 0xc00000c0180
//slice type is [] int, value is [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20], length is 20, capacity is 32, and address is 0xc00012c000

//Each slice expansion is a capacity multiplication, and the pointer address of its slice head changes. It can be seen that another memory is opened and copied during multiplication
4. Merger
/*Merge another slice*/
func BaseSlice04() {
    slice := []int{1, 2, 3, 4}
    fmt.Printf("slice1 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice, slice, len(slice), cap(slice))

    sli := []int{7, 8, 9}

    slice = append(slice, sli...) //Pay attention to "flattening" during Merger
    fmt.Printf("slice1 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice, slice, len(slice), cap(slice))

}

//slice1 type is [] int, value is [1 2 3 4], length is 4 and capacity is 4
//slice1 has a type of [] int, a value of [1 2 3 4 7 8 9], a length of 7 and a capacity of 8
5. Use the make() function to create slices
/*Creates a slice of the specified length and capacity*/
func BaseSlice05() {
    //Create an empty slice
    slice1 := make([]int, 0)
    fmt.Printf("slice1 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice1, slice1, len(slice1), cap(slice1))
    //slice1 type is [] int, value is [], length is 0 and capacity is 0


    //Creates an empty slice, but specifies the capacity
    slice2 := make([]int, 0, 5)
    fmt.Printf("slice2 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice2, slice2, len(slice2), cap(slice2))
    //slice2 is of type [] int, value [], length 0 and capacity 5


    //Create a slice with a length of 3 and a capacity of 5. The elements of the default length are initialized to zero
    slice3 := make([]int, 3, 5)
    fmt.Printf("slice3 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice3, slice3, len(slice3), cap(slice3))
    //slice3 is of type [] int, value [0], length 3 and capacity 5


    //Create a slice with a length of 5. The elements of the default length are initialized to zero. When the capacity is not specified, the capacity value is equal to the length value
    slice4 := make([]int, 5)
    fmt.Printf("slice4 Type is%T,Value is%v,Count Reg%d,Capacity%d\n", slice4, slice4, len(slice4), cap(slice4))
    //slice4 is of type [] int, value [0], length 5 and capacity 5
}
6. Delete slice element

go has no built-in slice deletion function, so deleting elements requires traversing slices

//Delete slice element
func RmSliceElement(slice []interface{}, index int) []interface{} {
    if index > len(slice)-1 {
        panic("index out of range")
    }

    for _, v := range slice {
        //If it is the last element
        if index == len(slice)-1 {
            return slice[:index]
        }
        //If it's an intermediate element
        if v == slice[index] {
            return append(slice[:index], slice[index+1:]...)
        }
    }

    return nil
}

3, Map map

1.map creation
//Create and initialize
m1 := map[string]string{
    "name":    "fun",
    "age":  "18",
    "gender":    "male",
}
    
//Create an empty map with a length of 5 and allocate memory
m2 := make(map[string]int,5)

//Only one map is declared and no memory is allocated
var m3 map[string]int 
    
fmt.Printf("m1:%v,Address is%p\n", m1,m1)
fmt.Printf("m2:%v,Address is%p\n", m2,m2)
fmt.Printf("m3:%v,Address is%p\n", m3,m3)
//m1:map[age:18 gender:male name:fun], address 0xc00008e480
//m2:map [], address 0xc00008e4b0
//m3:map [], address 0x0
2.map traversal and access value
//ergodic
m := map[string]string{
    "name":    "fun",
    "age":  "18",
    "gender":    "male",
}
for key, val := range m {
    fmt.Printf("Key:%s,Value:%v\n", key, val)
}
//Key:name,Value:fun
//Key:age,Value:18
//Key:gender,Value:male

//Access a key value
name := m["name"]
fmt.Printf("name:%v\n", name)
//name:fun

//Access a key that does not exist
names := m["names"]
fmt.Printf("names:%v\n", names)
//names:

//Access with verification
if a, ok := m["name"]; !ok {
    fmt.Println("key is not exist!")
} else {
    fmt.Println(a)
}
3. Delete map element

delete() is a built-in function, which is only valid for map

func BaseMap03() {
    m := map[string]string{
        "name":   "fun",
        "age":    "18",
        "gender": "male",
    }

    fmt.Printf("m: %v\n", m)

    delete(m, "age")
    fmt.Printf("m: %v\n", m)

}
//m: map[age:18 gender:male name:fun]
//m: map[gender:male name:fun]
4. Use of multidimensional map
//Use of multidimensional map
func BaseMap04() {
    //Declare the structure of a two-dimensional map
    var ms = make(map[string]map[string]int, 3)
    fmt.Printf("ms:Type:%T, Value: %v, Len:%d, Address:%p\n", ms, ms, len(ms), ms)

    //Internal initialization for 2D map
    ms["a"] = make(map[string]int, 4)
    ms["b"] = make(map[string]int, 5)
    ms["c"] = make(map[string]int, 6)
    fmt.Printf("ms:Type:%T, Value: %v, Len:%d, Address:%p\n", ms, ms, len(ms), ms)

    ms["d"] = make(map[string]int, 7)
    fmt.Printf("ms:Type:%T, Value: %v, Len:%d, Address:%p\n", ms, ms, len(ms), ms)

    //Assignment: assignment can only be performed after internal initialization of two-dimensional array
    //Otherwise, panic: assignment to entry in nil map is reported
    ms["a"]["aa"] = 1
    ms["a"]["bb"] = 2
    ms["a"]["cc"] = 3
    fmt.Printf("ms:Type:%T, Value: %v, Len:%d, Address:%p\n", ms, ms, len(ms), ms)

//[1]ms:Type:map[string]map[string]int, Value: map[], Len:0, Address:0xc000104300
//[2]ms:Type:map[string]map[string]int, Value: map[a:map[] b:map[] c:map[]], Len:3, Address:0xc000104300
//[3]ms:Type:map[string]map[string]int, Value: map[a:map[] b:map[] c:map[] d:map[]], Len:4, Address:0xc000104300
//[4]ms:Type:map[string]map[string]int, Value: map[a:map[aa:1 bb:2 cc:3] b:map[] c:map[] d:map[]], Len:4, Address:0xc000104300
}

4, About make() and new() functions

1.make()

Go has a built-in function to create slice, map and channel chan, that is, make().

Usage:

func make(Type, size IntegerType) Type

According to official documents:

  • Parameter 1 is a type, not a value, and the return type is the same as its parameter
  • Parameter 2 different types of parameters

Slice: size specifies its length. The capacity of the slice is equal to its length. Slicing supports the second integer argument, which can be used to specify different capacities; It must not be less than its length, so make([]int, 0, 10) will allocate a slice with length of 0 and capacity of 10.

Mapping: the creation of the initial allocation depends on size, but the resulting mapping length is 0. Size can be omitted, in which case a small starting size will be allocated.

Channel: the cache of the channel is initialized according to the specified cache capacity. If the size is zero or omitted, the channel is uncached.

2.new()

Usage:

func new(Type) *Type

The built-in function new allocates memory. Its first argument is a type, not a value. Its return value is a pointer to the newly assigned zero value of the type.

3. Difference between two functions
  • make() is specially used to create slices, maps and channels, allocate memory for them and initialize zero value. The returned slices, maps and channels are naturally pointer addresses.
  • new() generally allocates memory for creating any type other than the built-in reference type, but does not initialize data. It only sets the memory to zero and returns the * T pointer address. It is generally used to create array or struct value types. Of course, you can also use it to create basic data types and return pointer addresses.

Keywords: Go

Added by DannyM on Sat, 25 Dec 2021 03:36:57 +0200