Composite data types in the Go language

array

Arrays are a collection of elements of the same data type.In the Go language, an array is determined from the time it is declared and its members can be modified, but the size of the array cannot be modified.

Definition of arrays

The basic definition syntax for arrays is as follows:

var array name [array size] type

For example, define an array of length 3 and type int:

var a [3]int

Note: Length must be a constant, it is part of the array type, once defined, the length cannot be changed.

Initialization of arrays

(1) When initializing an array, you can use the initialization list to set the values of the array elements.

func main() {
    var testArray [3]int                        //Array is initialized to zero value of type int
    var numArray = [3]int{1, 2}                 //Complete the initialization with the specified initial value
    var cityArray = [3]string{"Beijing", "Shanghai", "Shenzhen"} //Complete the initialization with the specified initial value
    fmt.Println(testArray)                      //[0 0 0]
    fmt.Println(numArray)                       //[1 2 0]
    fmt.Println(cityArray)                      //[Beijing, Shanghai, Shenzhen]
}

(2) Follow the above method to ensure that the initial values provided are the same as the array length each time. In general, we can let the compiler infer the length of the array by itself based on the number of initial values, for example:

func main() {
    var testArray [3]int
    var numArray = [...]int{1, 2}
    var cityArray = [...]string{"Beijing", "Shanghai", "Shenzhen"}
    fmt.Println(testArray)                          //[0 0 0]
    fmt.Println(numArray)                           //[1 2]
    fmt.Printf("type of numArray:%T\n", numArray)   //type of numArray:[2]int
    fmt.Println(cityArray)                          //[Beijing, Shanghai, Shenzhen]
    fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}

(3) We can also initialize the array by specifying the index value, for example:

func main() {
    a := [...]int{1: 1, 3: 5}
    fmt.Println(a)                  // [0 1 0 5]
    fmt.Printf("type of a:%T\n", a) //type of a:[4]int
}

Traversal of arrays

There are two ways to traverse an array:

  • for range
  • Traversing through indexes

The following:

package main

import "fmt"

func main() {
    var a = [...]string{"Beijing", "Shanghai", "Guangzhou"}
    // Traversing through arrays by index
    for i := 0; i < len(a); i++ {
        fmt.Println(a[i])
    }
    fmt.Println("================")

    // Traversing an array with for range
    for _, v := range a {
        fmt.Println(v)
    }
}

Multidimensional Array

The Go language supports multidimensional arrays, for example, two-dimensional arrays.

Definition of a two-dimensional array

The basic definition of a two-dimensional array is as follows:

var array name [array size] [array size] type

As shown below, the outer array has three elements and the inner array has two two-dimensional arrays:

var a [3][2]int

Initialization of a two-dimensional array

package main

import "fmt"

func main() {
    var cities = [3][2]string{
        {"Beijing", "Shanghai"},
        {"Guangzhou", "Chongqing"},
        {"Sichuan", "Guizhou"},
    }
    fmt.Println(cities)
}

If you want to derive the length of an array automatically, only the first level can be used, as follows:

//Supported Writing
a := [...][2]string{
    {"Beijing", "Shanghai"},
    {"Guangzhou", "Shenzhen"},
    {"Chengdu", "Chongqing"},
}
//Inside use of multidimensional arrays is not supported...
b := [3][...]string{
    {"Beijing", "Shanghai"},
    {"Guangzhou", "Shenzhen"},
    {"Chengdu", "Chongqing"},
}

Note: Arrays are of value type, and their assignments and arguments copy the entire array, so changing the value of the copy does not change its own value.The following:

package main

import "fmt"

func main() {
    var cities = [3][2]string{
        {"Beijing", "Shanghai"},
        {"Guangzhou", "Chongqing"},
        {"Sichuan", "Guizhou"},
    }
    // fmt.Println(cities)
    c2 := cities
    c2[2][0] = "Heilongjiang"
    fmt.Println(cities)
    fmt.Println(c2)
}

The output is:

[[Beijing Shanghai] [Guangzhou Chongqing] [Sichuan Guizhou]]
[[Beijing, Shanghai] [Guangzhou, Chongqing] [Heilongjiang, Guizhou]]

3.3. Slices

The length of an array is immutable, and once we define an array, its length is fixed.Slices, on the other hand, are a layer of encapsulation of arrays, which are variable-length sequences with the same type of elements.It is very flexible and supports automatic expansion.

A slice is a reference type, and its underlying layer is still an array. If the underlying data changes, the slice changes accordingly.The contents of the slice include the address length capacity.It is generally used to quickly manipulate a data collection.

Custom Slice

The basic syntax for slicing is as follows:

var variable name [] element type

Note: When defining a slice, you do not specify its length.

For example:

package main

import "fmt"

func main() {
    // Define Slice
    var s1 []int
    var s2 []string
    var s3 []bool
    fmt.Println(s1, s2, s3)
}

Because the slice is a reference type, it does not support direct comparisons, only nil comparisons, as follows:

package main

import "fmt"

func main() {
    // Define Slice
    var s1 []int
    var s2 []string
    var s3 []bool
    fmt.Println(s1, s2, s3)
    fmt.Println(s1 == nil)
    fmt.Println(s2 == nil)
    fmt.Println(s3 == nil)
    // fmt.Println(s1 == s3)//Can't be compared this way
}

Initialization of custom slices

Slices are initialized as arrays, because the underlying layer is itself an array.For example:

package main

import "fmt"

func main() {
    // Define slices and initialize
    var s4 = []int{1, 2, 3, 4}
    var s5 = []string{"Beijing", "Shanghai"}
    var s6 = []bool{true, false}
    fmt.Println(s4, s5, s6)
}

Define slices based on arrays

We know that the bottom layer of a slice is storage, so slices can also be defined based on arrays.The following:

package main

import "fmt"

func main() {
    // Define slices based on arrays
    // Define an array first
    var a1 = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    // Then cut the array
    var a2 = a1[2:6]
    var a3 = a1[1:]
    var a4 = a1[:4]
    var a5 = a1[:]
    fmt.Println(a1, a2)
}

Define slices based on slices

Slices can also define slices based on them.The following:

package main

import "fmt"

func main() {
    // Define slices based on slices
    // Define a slice
    var s = []int{1,2,3,4,5,6,7,8,9}
    // Cutting slices
    var s1 = s[2:4]
    fmt.Println(s1)
}

Note: When a slice is re-sliced, its index cannot exceed the length of the original array.

Slice length and capacity

Slices have their own length and capacity, and we can find the length by using the built-in len() function and the capacity by using the built-in cap() function.

package main

import "fmt"

func main() {
    // Define slices based on slices
    // Define a slice
    var s = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    // Cutting slices
    var s1 = s[2:4]
    fmt.Println(s1)
    fmt.Printf("len(s1):%d  cap(s1):%d", len(s1), cap(s1))
}

The output is as follows:

[3 4]
len(s1):2  cap(s1):7

Explain:

  • The length computed by the len function is the existing length of the slice
  • The cap function calculates the capacity from the beginning of the slice to the end of the array

Slice construction using make function

All of the above is about defining slices from arrays, where the length and capacity are fixed at the time of definition, whether by customization or from an array slice.Then, if we need to create a slice dynamically, we need to use the make function in the following format:

make([]T, size, cap)

Explain:

  • T: Represents the type of element
  • size: indicates the number of elements
  • cap: indicates the capacity of the slice

For example, we create a slice with 5 elements and 10 capacities.

package main

import "fmt"

func main() {
    s := make([]int, 5, 10)
    fmt.Println(s)
    fmt.Printf("len(s):%d cap(s):%d\n", len(s), cap(s))
}

The output is as follows:

[0 0 0 0 0]
len(s):5 cap(s):10

If we do not specify a capacity, the default is the same number of elements as the previous one, as follows:

package main

import "fmt"

func main() {
    s := make([]int, 5)
    fmt.Println(s)
    fmt.Printf("len(s):%d cap(s):%d", len(s), cap(s))
}

The output is as follows:

[0 0 0 0 0]
len(s):5 cap(s):5

The nature of slicing

The essence of a slice is an encapsulation of a low-level array, which contains three information: the pointer to the low-level array, the length of the slice (len), and the capacity of the slice (cap).

For example, there is an array a: = [8] int{0, 1, 2, 3, 4, 5, 6, 7}, slice s1: = a[:5], the corresponding diagram is as follows.

Slice s2: = a[3:6], the corresponding diagram is as follows:

There is no comparison between slices, and we cannot use the == operator to determine if two slices contain all the same elements.The only legal comparison of slices is with nil.A slice of nil value has no underlying array, and the length and capacity of a slice of nil value are both 0.But we cannot say that a slice with length and capacity of 0 must be nil, for example, in the following example:

var s1 []int         //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{}        //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil

So to determine if a slice is empty, if you use len(s) == 0 to judge, you should not use s == nil to judge.

Notice the following three points:

  • Slices do not save specific values
  • Slices correspond to a bottom array
  • The underlying arrays occupy a contiguous block of memory space

Assignment copy of slice

We know that slices are essentially encapsulation of the underlying array and are a reference type, so if two slices share the underlying array, modifying one slice can affect the contents of the other, as follows:

package main

import "fmt"

func main() {
    s := make([]int, 5)
    fmt.Println(s)
    fmt.Printf("len(s):%d cap(s):%d\n", len(s), cap(s))
    s1 := s
    s1[0] = 100
    fmt.Println(s)
    fmt.Println(s1)
}

The output is as follows:

[0 0 0 0 0]
len(s):5 cap(s):5
[100 0 0 0 0]
[100 0 0 0 0]

Copying Slices Using the copy Function

The assignment copy described above, where two slices share the same underlying array, modifying either slice will affect the other.In the Go language, there is another function, copy(), that opens up another memory space to hold the copied slices, through which the copied slices have no relationship with the original slices.

Its basic syntax is as follows:

copy(destSlice, srcSlice)

Where:

  • destSlice: is the target slice
  • srcSlice: is the source slice

For example:

package main

import "fmt"

func main() {
    // Define a slice and initialize it
    s1 := []int{1, 2, 3, 4}
    // Define another slice
    s2 := make([]int, 4, 4)
    // Copy with copy() function
    copy(s2, s1)
    // Output: Source Slice s1:[1 2 3 4]Target Slice s2:[1 2 3 4]
    fmt.Printf("Source Slice s1: %v  Target Slice s2:%v\n", s1, s2)
    // Modify the source slice to see if the target slice changes
    s1[0] = 100
    // Output: Source Slice s1:[100 2 3 4]Target Slice s2:[1 2 3 4]
    fmt.Printf("Source Slice s1: %v  Target Slice s2:%v\n", s1, s2)
    // Modify the target slice to see if the source slice changes
    s2[1] = 300
    // Output: Source Slice s1:[100 2 3 4]Target Slice s2:[1 300 3 4]
    fmt.Printf("Source Slice s1: %v  Target Slice s2:%v\n", s1, s2)
}

As you can see above, the slices copied with copy do not affect each other before.

Traversal of slices

Slices are traversed as arrays, as follows:

package main

import "fmt"

func main() {
    s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    // First: Traversing the index
    for i := 0; i < len(s); i++ {
        fmt.Println(s[i])
    }
    // Second: traversing with for range
    for i, v := range s {
        fmt.Println(i, v)
    }
}

Add elements to slices

As mentioned above, if the length of the slice is not fixed, then we can add new content to the slice.In the Go language, append() is used to add content to a slice.

Be careful:

  1. If the capacity of the slice is sufficient, add content directly to the slice;
  2. If the capacity of the slice is insufficient, it will be expanded by a certain strategy before adding content to it.

For example:

package main

import "fmt"

func main() {
    // Define an array
    a := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    // Then get a slice from the array
    s := a[:4]
    // Then print the length and capacity of the slice, when the length is less than the capacity.
    // Output: [1 2 3 4] len(s):4 cap(s):9
    fmt.Printf("%v len(s):%d cap(s):%d\n", s, len(s), cap(s))
    // We add elements to slices s
    s = append(s, 100)
    // Output: [1 2 3 4 100] len(s):5 cap(s):9
    fmt.Printf("%v len(s):%d cap(s):%d\n", s, len(s), cap(s))

    // We get a slice from the array again, this time using the full amount of
    s2 := a[:]
    // Output: [1 2 3 4 100 6 7 8 9] len(s2):9 cap(s2):9
    fmt.Printf("%v len(s2):%d cap(s2):%d\n", s2, len(s2), cap(s2))
    // We add elements to it
    s2 = append(s2, 200)
    // Output: [1 2 3 4 100 6 7 8 9 200] len(s2):10 cap(s2):18
    fmt.Printf("%v len(s2):%d cap(s2):%d\n", s2, len(s2), cap(s2))

}

The output above just validates what we say: if the capacity of the slice is sufficient, add elements directly and then append; if the capacity of the slice is insufficient, add elements first to expand capacity, then add elements later.

Of course, the append() function also supports expanding multiple elements at once, as follows:

package main

import "fmt"

func main() {
    // Define an array
    a := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    // We get a slice from the array again, this time using the full amount of
    s2 := a[:]
    // Output: [1 2 3 4 100 6 7 8 9] len(s2):9 cap(s2):9
    fmt.Printf("%v len(s2):%d cap(s2):%d\n", s2, len(s2), cap(s2))
    // We add elements to it
    s2 = append(s2, 200)
    // Output: [1 2 3 4 100 6 7 8 9 200] len(s2):10 cap(s2):18
    fmt.Printf("%v len(s2):%d cap(s2):%d\n", s2, len(s2), cap(s2))
    s2 = append(s2, 300, 400, 500)
    fmt.Printf("%v len(s2):%d cap(s2):%d\n", s2, len(s2), cap(s2))
}

Tile Expansion Strategy

By adding elements to the slices above, you know that when the capacity of the slices is insufficient, they will be expanded first.There are also some strategies for expansion, which are as follows:

  1. If the application capacity is more than twice the original capacity, the final capacity is the size of the application capacity.
  2. If the capacity of old slices is less than 1024, the final capacity is twice that of old slices.
  3. If the capacity of the old slice is greater than 1024, the final capacity will increase by one-fourth from the beginning of the old capacity cycle until the final capacity is greater than or equal to the capacity of the new application.
  4. If the final capacity calculation value overflows, the final capacity is the new application capacity.

Note: Tile expansion can also be handled differently depending on the type of elements in the slice, such as int and string.

Remove elements from slices

There is no special way to delete slice elements in the Go language, but we can use the properties of the slice itself to delete elements.

For example, to delete elements that are considered index in slice a, use the following method:

a = append(a[:index], a[index+1:]...)

For example:

package main

import "fmt"

func main() {
    // Define a slice
    s1 := []int{1, 2, 3, 4, 5}
    // Remove elements with a value of 3 from the slice
    s1 = append(s1[:2], s1[3:]...)
    // Output: [1 2 4 5]
    fmt.Println(s1)
}

How does deleting an element from a slice affect the original array?Let's look at the following example:

package main

import "fmt"

func main() {
    // Define an array
    a := [...]int{1, 2, 3, 4, 5, 6}
    s2 := a[:]
    s2 = append(s2[:2], s2[3:]...)
    fmt.Println(s2) // Output: [1 2 4 5 6]
    fmt.Println(a)  // Output: [1 2 4 5 6]
}

We can see that deleting an element from a slice also has an effect on the original data.As follows:

Tags: Go less

Posted on Sun, 15 Mar 2020 13:23:24 -0400 by susannah