The previous article introduced the basic language of Go in detail, and pointed out the differences between Go and other mainstream programming languages. It focuses on the details of syntax, and I believe it is easy to switch from existing programming languages to Go with a little memory While the switch may not be particularly smooth, with practice and especially trial and error, you can always appreciate the beauty of Go!

Before learning about Go’s built-in containers, let’s briefly review the basic language of Go.

Review of the last video

If you need to know more details, please check the basic grammar articles worthy of special attention in the wechat public number [Snow dream technology station]. If you feel useful, please forward them.

Built-in type types

  • bool

Boolean type, optional true | false, the default initialization of zero value is false.

  • (u)int ,(u)int8 , (u)int16.(u)int32.(u)int64.uintptr

2^0=1,2^1=2,2^2=4 bytes of integer, including signed and unsigned integer and uintptr type pointer type, default initialization zero value 0.

  • byte(uint8) ,rune(int32).string

Byte, the most basic byte type, is an alias for the Uint8 type, while Rune, the character type in Go, is an alias for Int32. The most common type of string is string.

  • float32 ,float64 ,complex64 ,complex128

Floating-point is a complex type of which float32 is a composite of the real and virtual parts. Complex64 is a complex64 of float32.

Built-in type characteristics

  • Type conversions are only display conversions, and there is no implicit type conversion of any kind

Implicit type conversions between different variable types are not automatically performed. Type conversions in Go are only mandatory and can only be displayed.

  • Although a pointer type is provided, the pointer itself cannot be evaluated in any way.

A pointer type variable cannot be evaluated, but can be redirected to a memory address.

  • After a variable is declared, it is initialized with zero value by default, depending on the specific type

Int initialzero is 0,string initialzero is an empty string, not nil

Basic operator

  • The arithmetic operator does not++i--i

Only I ++ and I – this increment operation, no longer need to worry about the difference between the two methods!

  • Comparison operator= =You can compare arrays for equality

Two arrays can be compared when their dimensions and lengths are equal, and in exactly the same order, the result is true, otherwise false.

  • Bitwise operator Added bitwise zeroing operator& ^

Other major programming languages do not have this operator and can achieve similar functionality by combining commands, but since they provide bitwise zeroing operators, you don’t need to combine them yourself anymore!

Flow control statement

  • ifConditional expressions do not require parentheses and support variable assignment operations

First define temporary variables and logical judgment according to the variable, and then according to different situations for classification processing,Go processing this temporary variables, directly to the conditional expression enhancement, this kind of situation will be very common!

  • ifVariables defined within a conditional expression are scoped only to the current statement block

Variables defined in conditional expressions are intended to facilitate handling of different branches of logic, and since they are temporary variables, they are not usable outside the current if block and become understandable.

  • switchStatements can be withoutbreakUnless usedfallthrough

If there is no break at the end of multiple cases in a switch statement, the system will automatically process the break.

  • switchConditional expressions are not limited to constants or integers

Go’s switch conditional expressions are more powerful and looser than those of other major programming languages.

  • switchConditional expressions can be omitted and branch logic turnedcaseLanguage implementation.

Omit switch condition expression, multiple case languages for branch flow control, function effect is the same as multiple if else.

  • omitswitchConditional expression after eachcaseConditions can have more than one condition, separated by commas.

The essence of SWICTH statement is to control the process according to different conditions. The condition expression of each case supports more than one, which enhances the ability of process control.

  • forConditional expressions for loops also do not require parentheses, and there are no other forms of loops.

Go has only for loops, not while loops.

  • forThe initial condition, termination condition, and increment expression of the loop can all be omitted or omitted at the same time

A conditional expression can be omitted to achieve the effect of a while loop, while all omissions are an infinite loop.

Function and parameter passing

  • Function declarations are defined by function name, input parameter, and output parameter order, and support multiple return values

Whether it’s a variable definition or a function definition,Go is always the opposite of other major programming languages, which makes sense if you think about it in terms of input and output.

  • When a function has more than one return value, the return value can be named, but it makes no difference to the caller

A function that returns multiple values can have a variable name, which makes it easier for the caller to quickly become familiar with the function declaration, but the caller is not required to receive the result of the call according to the return value name.

  • The input parameters of a function have no complex concepts such as mandatory or optional parameters, and only variable parameter lists are supported

Mutable argument lists, as in other mainstream programming languages, must be the last input parameter.

  • Function parameters pass only value, no reference pass, that is, all need to copy variables

Parameter passing only has value passing, which is logically simpler, but in complex cases Pointers can be passed to achieve the effect of reference passing.

What are the built-in containers

After reviewing the basic syntax of Go, I continued to learn about the bearers of variable types, namely containers.

The most basic container for a class of variables is an array. Most advanced containers can be wrapped by an array. So let’s see how the array of Go is different.

Arrays and slices

  • Array declaration and initialization

An array is a set of contiguous storage Spaces of a specified length. When you declare an array, you must specify the length of the array. The syntax lets the compiler help us determine the length of the array.

func TestArray(t *testing.T) {
    var arr1 [3]int
    arr2 := [5]int{1.2.3.4.5}
    arr3 := [...]int{2.4.6.8.10}

    // [0 0 0] [1 2 3 4 5] [2 4 6 8 10]
    t.Log(arr1, arr2, arr3)

    var grid [3] [4]int

    // [[0 0 0 0 0] [0 0 0 0 0]]
    t.Log(grid)
}
Copy the code

[3]int int{1, 2, 3, 4, 5} [5]int{1, 2, 3, 4, 5} Int {2, 4, 6, 8, 10}

  • Array traversal and element access

The most common for loop traversal is to access the array index. Range ARR provides a convenient way to simplify traversal.

func TestArrayTraverse(t *testing.T) {
    arr := [...]int{2.4.6.8.10}

    for i := 0; i < len(arr); i++ {
        t.Log(arr[i])
    }

    for i := range arr {
        t.Log(arr[i])
    }

    for i, v := range arr {
        t.Log(i, v)
    }

    for _, v := range arr {
        t.Log(v)
    }
}
Copy the code

Range arr can return index values and items. If you only care about the item and don’t care about the value of the index, you can use the _ placeholder to indicate that the index value is ignored. If you only care about the value of the index, you don’t need to write the item. The processing logic is that multiple return values of the function are received sequentially, and unused variables are not allowed.

  • Arrays are value types that can be compared

Arrays are value types, unlike other mainstream programming languages, so arrays of the same latitude with the same number of elements can be compared. This has already been emphasized, so here’s a quick review.

func printArray(arr [5]int) {
    arr[0] = Awesome!
    for i, v := range arr {
        fmt.Println(i, v)
    }
}

func TestPrintArray(t *testing.T) {
    var arr1 [3]int
    arr2 := [5]int{1.2.3.4.5}
    arr3 := [...]int{2.4.6.8.10}

    // [0 0 0] [1 2 3 4 5] [2 4 6 8 10]
    t.Log(arr1, arr2, arr3)

    // cannot use arr1 (type [3]int) as type [5]int in argument to printArray
    //printArray(arr1)

    fmt.Println("printArray(arr2)")
    printArray(arr2)

    fmt.Println("printArray(arr3)")
    printArray(arr3)

    // [1 2 3 4 5] [2 4 6 8 10]
    t.Log(arr2, arr3)
}
Copy the code

Since argument passing is value passing, printArray cannot change the value of the external function passed by the caller. If you want to change the contents of the array passed inside printArray, you can do so by using a pointer, but is there an easier way to do this?

To modify an array of parameters inside printArrayByPointer, use an array pointer. If you’re not familiar with this, you can review the previous article.

func printArrayByPointer(arr *[5]int) {
    arr[0] = Awesome!
    for i, v := range arr {
        fmt.Println(i, v)
    }
}

func TestPrintArrayByPointer(t *testing.T) {
    var arr1 [3]int
    arr2 := [5]int{1.2.3.4.5}
    arr3 := [...]int{2.4.6.8.10}

    // [0 0 0] [1 2 3 4 5] [2 4 6 8 10]
    t.Log(arr1, arr2, arr3)

    fmt.Println("printArrayByPointer(arr2)")
    printArrayByPointer(&arr2)

    fmt.Println("printArrayByPointer(arr3)")
    printArrayByPointer(&arr3)

    // [666 2 3 4 5] [666 4 6 8 10]
    t.Log(arr2, arr3)
}
Copy the code

The elements of an array can be modified by passing Pointers to the array. In addition, a close cousin of arrays in Go, slice, can achieve a similar effect.

  • Declaration and initialization of slices

Slicing is very similar to an array. If you create an array without specifying the length of the array, you end up creating a slice, not an array.

func TestSliceInit(t *testing.T) {
    var s1 [5]int
    // [0 0 0 0 0]
    t.Log(s1)

    var s2 []int
    / / []
    t.Log(s2,len(s2))
}
Copy the code

[] array_size = 0 [] array_size = 0 [] array_size = 0 []

Similarly, arrays can be declared and initialized, as can slicing, and the syntax is similar.

func TestSliceInitValue(t *testing.T) {
    var s1 = [5]int{1.3.5.7.9}
    // [1 3 5 7 9]
    t.Log(s1)

    var s2 = []int{1.3.5.7.9}
    // [1 3 5 7 9]
    t.Log(s2)
}
Copy the code

Simply by not specifying the length in [], you end up creating slices that are really dazzling!

Arrays and slices are so similar that one has to wonder what’s going on between them. You can actually get slices from an array, as shown in the following example:

func TestSliceFromArray(t *testing.T) {
    arr := [...]int{0.1.2.3.4.5.6.7.8.9}
    // arr = [0 1 2 3 4 5 6 7 8 9]
    t.Log("arr = ", arr)

    // arr[2:6] = [2 3 4 5]
    t.Log("arr[2:6] = ", arr[2:6])
    // arr[:6] = [0 1 2 3 4 5]
    t.Log("arr[:6] = ", arr[:6])
    // arr[2:] = [2 3 4 5 6 7 8 9]
    t.Log("arr[2:] = ", arr[2:)// arr[:] = [0 1 2 3 4 5 6 7 8 9]
    t.Log("arr[:] = ", arr[:])
}
Copy the code

Arr [start:end] sectionalizes a portion of an array.

Like other major programming languages,[start:end] is a closed left open right interval, and the meaning of slicing is very clear:

If start is ignored,arr[:end] indicates the beginning of the array until the first bit of the end index is terminated. If end is ignored,arr[start:] indicates that the array starts from the start index to the last digit; Omit both the start index and the end index, although not common, but should be the original array, but remember that the type is slice not array!

So far, we know that slices are similar to arrays. Slices have no size relative to arrays. Do they operate the same?

func updateSlice(s []int) {
    s[0] = Awesome!
}

func TestUpdateSlice(t *testing.T) {
    arr := [...]int{0.1.2.3.4.5.6.7.8.9}

    // arr = [0 1 2 3 4 5 6 7 8 9]
    t.Log("arr = ", arr)
    
    s1 := arr[2:6]
    // s1 = [2 3 4 5]
    t.Log("s1 = ", s1)

    s2 := arr[:6]
    // s2 = [0 1 2 3 4 5]
    t.Log("s2 = ", s2)

    updateSlice(s1)
    // s1 = [666 3 4 5]
    t.Log("s1 = ", s1)
    // arr = [0 1 666 3 4 5 6 7 8 9]
    t.Log("arr = ", arr)

    updateSlice(s2)
    // s2 = [666 1 666 3 4 5]
    t.Log("s2 = ", s2)
    // arr = [666 1 666 3 4 5 6 7 8 9]
    t.Log("arr = ", arr)
}
Copy the code

Slicing can actually change the passing parameters, which arrays can’t do! How can slicing be done easily unless you use an array pointer type? Unless there is a pointer inside the slice, because parameters are only passed by value, there is no reference at all!

Slice and array in the performance of parameter transfer is different, specific performance for the array parameter transfer can not modify the array, want to change the array only to pass the array pointer, but slice has realized the array change!

Since there is only one way of parameter transfer, it is speculated that there must be a pointer inside the slice. When the parameter is passed, the pointer is passed, so the modification inside the function can affect the variables outside the function.

Slice’s internal implementation has three variables, Pointers to PTR, len, and Cap, where the PTR points to the actual data store address.

It is precisely because of the internal implementation of slicing, the need for features or representation that the switch and array have a lot of links, in fact, this data result is an extension of the static array, essentially a dynamic array, but Go language is called slicing!

Slicing is a dynamic array, so the above problem is easily explained. When passing parameters, internal Pointers are passed. Therefore, although the pointer is copied in value passing, the real elements that the pointer points to are the same after all, so slicing can modify the value of external parameters.

Arrays can be compared to some extent, slices are dynamic arrays, can they be compared? Let the following test prove your guess!

I wonder if you guessed correctly. Slices can’t be compared, they can only be judged against nil.

  • Adding and removing slices

Array is a static structure, the size of the array can not be expanded or reduced, this data structure can not meet the uncertain number of elements scene, so the dynamic array slicing, next focus on how to slice to add or delete elements.

func printSlice(s []int) {
    fmt.Printf("s = %v, len(s) = %d, cap(s) = %d\n", s, len(s), cap(s))
}

func TestSliceAutoLonger(t *testing.T) {
    var s []int
    / / []
    t.Log(s)

    for i := 0; i < 10; i++ {
        s = append(s, i)

        printSlice(s)
    }

    // [0 1 2 3... 98,99]
    t.Log(s)

    for i := 0; i < 10; i++ {
        s = s[1:]
        
        printSlice(s)
    }

    // [0 1 2 3... 98,99]
    t.Log(s)
}
Copy the code

Add element s = append(s, I) If capacity expansion is required, expand capacity by twice each time. If element S [1:] is deleted, the capacity reduction will be decreased.

s = append(s, I) is added to the slice element and returns the new section, because of the slice is a dynamic array, automatic expansion when slicing internal array length is not enough to accommodate the new array, before and after the expansion of internal process of array elements to copy, so the append will return to the new address, expansion after the address is not the original, so need to use variable after receiving add sliced.

When slices are continuously re-intercepted, s[1:], the elements stored in slices begin to shrink, with decreasing number and capacity.

In fact, in addition to creating slices based on arrays and directly creating slices, there is a third way to create slices, which is also the most commonly used way, and that is the make function.

func TestMakeSlice(t *testing.T) {
    s1 := make([]int.10)

    // s1 = [0 0 0 0 0 0 0 0 0 0], len(s1) = 10, cap(s1) = 10
    t.Logf("s1 = %v, len(s1) = %d, cap(s1) = %d", s1, len(s1), cap(s1))

    s2 := make([]int.10.32)

    // s2 = [0 0 0 0 0 0 0 0 0 0], len(s2) = 10, cap(s2) = 32
    t.Logf("s2 = %v, len(s2) = %d, cap(s2) = %d", s2, len(s2), cap(s2))
}
Copy the code

You can use make to set the initial length and capacity of slices, which is not possible when creating slices with literals. It also supports bulk copy!

func TestCopySlice(t *testing.T) {
    var s1 = []int{1.3.5.7.9}
    var s2 = make([]int.10.32)

    copy(s2, s1)

    // s2 = [1 3 5 7 9 0 0 0 0 0], len(s2) = 10, cap(s2) = 32
    t.Logf("s2 = %v, len(s2) = %d, cap(s2) = %d", s2, len(s2), cap(s2))

    var s3 []int

    copy(s3, s1)

    // s3 = [], len(s3) = 0, cap(s3) = 0
    t.Logf("s3 = %v, len(s3) = %d, cap(s3) = %d", s3, len(s3), cap(s3))
}
Copy the code

Func copy(DST, SRC []Type) int (DST, SRC []Type] int) func copy(DST, SRC []Type) int

The underlying structure of a slice is a dynamic array. If a slice is truncated based on an array, then the slice at this time is a view of the original array in effect, and any operation on the slice will be reflected on the original array, which is also quite understandable.

So how about slicing slices again, or whether slicing would cross the line, it’s actually a little bit easier, but I’ll show you a little bit more about the underlying structure of the dynamic array.

func TestSliceOutOfBound(t *testing.T) {
    arr := [...]int{0.1.2.3.4.5.6.7}

    s1 := arr[2:6]
    // s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 6
    t.Logf("s1 = %v, len(s1) = %d, cap(s1) = %d", s1, len(s1), cap(s1))

    s2 := s1[3:5]
    // s2 = [5 6], len(s2) = 2, cap(s2) = 3
    t.Logf("s2 = %v, len(s2) = %d, cap(s2) = %d", s2, len(s2), cap(s2))
}
Copy the code

[] can only access elements in len(arr),[:] can only access elements in Cap (arr), generally cap >= len, so some cases look out of bounds, but not out of bounds, just the two criteria are different!

We know that the internal data structure of slice is based on dynamic array. There are three important variables, namely pointer PTR, number Len and capacity CAP. Understand how these three variables implement dynamic array.

Number Len is the effective range of access by subscript, exceeding len will report an out-of-bounds error, and capacity cap is the maximum range that can be seen later, the essence of dynamic array is to control these two variables to achieve effective array access.

Because s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 6, so the range of [] accessing slice s1 element is [0,4], thus the maximum access to s1[3], and s1[4] is out of bounds!

Because s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 6, so [:] the scope of creating a new slice based on slice s1 is [0,6], so the maximum accessible scope is s1[0:6], and s1[3:7] is out of bounds!

A collection ofmap

A collection is a data structure composed of key-value pairs, a concept similar to that of other major programming languages, but Go’s Map can load a much more diverse set of data types.

  • Literal creationmapKeep commas for newlines.
func TestMap(t *testing.T) {
    m1 := map[string]string{
        "author": "snowdreams1006"."website": "snowdreams1006"."language": "golang",}// map[name:snowdreams1006 site:https://snowdreams1006.github.io]
    t.Log(m1)
}
Copy the code

It makes sense to have a comma at the end of a key-value pair, but it makes sense to me to have a comma at the end of a key-value pair. Why?

  • makeTo create themapAnd literals createdmapThe default initialization zero value is different
func TestMapByMake(t *testing.T) {
    // empty map
    m1 := make(map[string]int)

    // map[] false
    t.Log(m1, m1 == nil)

    // nil
    var m2 map[string]int

    // map[] true
    t.Log(m2, m2 == nil)}Copy the code

The make function creates an empty map and a literal map is nil. The same rule applies to slice.

  • rangetraversemapIs chaotic
func TestMapTraverse(t *testing.T) {
    m := map[string]string{
        "name": "snowdreams1006"."site": "https://snowdreams1006.github.io",}// map[name:snowdreams1006 site:https://snowdreams1006.github.io]
    t.Log(m)

    for k, v := range m {
        t.Log(k, v)
    }

    t.Log()

    for k := range m {
        t.Log(k)
    }

    t.Log()

    for _, v := range m {
        t.Log(v)
    }
}
Copy the code

Range traversal is the same as array and slice traversal. The only difference is that the map has no index and the traversal result is unordered!

  • The element is retrieved to determine whether it exists
func TestMapGetItem(t *testing.T) {
    m := map[string]string{
        "name": "snowdreams1006"."site": "https://snowdreams1006.github.io",}// snowdreams1006
    t.Log(m["name"])

    // zero value is empty string
    t.Log(m["author"])

    // https://snowdreams1006.github.io
    if site, ok := m["site"]; ok {
        t.Log(site)
    } else {
        t.Log("key does not exist ")}}Copy the code

Map [string] String returns the default zero value as an empty string. Since there is no error notification, this requires us to do an extra check when calling. The second return value returns true if the key-value pair exists and false if it does not.

  • Used to delete key-value pairsdeletefunction
func TestMapDeleteItem(t *testing.T) {
    m := map[string]string{
        "name": "snowdreams1006"."site": "https://snowdreams1006.github.io",}// map[name:snowdreams1006 site:https://snowdreams1006.github.io]
    t.Log(m)

    delete(m, "name")

    // map[site:https://snowdreams1006.github.io]
    t.Log(m)

    delete(m, "id")

    // map[site:https://snowdreams1006.github.io]
    t.Log(m)
}
Copy the code

Delete (map,key) is used to delete a map key-value pair. If you want to verify that the map is successfully deleted, do not forget to use value, OK := m[k] to determine whether the specified key-value pair exists

  • In addition toslice.map.funcOther types can be keyed

Because map is implemented based on a hash table, traversal is unordered, and because slice,map, and func are not comparable and cannot be used as keys. Of course, if a custom struc does not contain the above type, it can also be used as a key, and does not require implementation of hashcode or equal.

  • valueCan carry functionfunctype
func TestMapWithFunValue(t *testing.T) {
    m := map[int]func(op int) int{}

    m[1] = func(op int) int {
        return op
    }
    m[2] = func(op int) int {
        return op * op
    }
    m[3] = func(op int) int {
        return op * op * op
    }

    / / 1 April 27
    t.Log(m[1] (1), m[2] (2), m[3] (3))}Copy the code

Once again, functions are first-class citizens, which will be covered in more detail in functional programming.

There is noset

The default type of Go does not have a data structure like set, which is unusual in mainstream programming languages.

Just as the Go loop only supports the for loop, the while loop can be played without the while loop, thanks to the enhanced FOR capability.

Therefore, even if there is no set type, the set effect can be implemented based on the existing data structure, of course, the map can be directly encapsulated into a set.

func TestMapForSet(t *testing.T) {
    mySet := map[int]bool{}

    mySet[1] = true

    n := 3

    if mySet[n] {
        t.Log("update", mySet[n])
    } else {
        t.Log("add", mySet[n])
    }

    delete(mySet, 1)}Copy the code

Use map[type]bool encapsulation to implement set’s feature of disallowing repeatable elements. This will be encapsulated in the object-oriented section, but only the core structure is listed here.

Summary of knowledge points

The Go language is very concise, both in its basic syntax and the built-in containers in this section.

Array is the basic data structure of each programming language. Go language is no different from other mainstream programming languages in that it is a piece of continuous storage space. The difference is that arrays are value types, so they can also be compared.

This isn’t new knowledge, as we covered it in detail in the previous section, which focused on slice, a derivative of arrays.

Because the array itself is a specific length of continuous space, because it is immutable, other mainstream programming languages have corresponding solutions, including a lot of data structure is based on the array,Go language slice is the same, so I prefer to call it dynamic array in my heart!

Slice is a simple design with three important variables, including array pointer PTR, accessible element length Len, and allocated capacity CAP.

When new elements are constantly added into the slice, it will always reach the maximum allocated capacity, at this time the slice will automatically expand, otherwise it will shrink, so as to achieve the ability of dynamic control!

  • A specified number of elements is an array, and an unspecified number is a slice
func TestArrayAndSlice(t *testing.T) {
    // array
    var arr1 [3]int
    // slice
    var arr2 []int

    // [0 0 0] []
    t.Log(arr1,arr2)
}
Copy the code
  • A slice created based on an array is a view of the original array
func TestArrayAndSliceByUpdate(t *testing.T) {
    arr := [...]int{0.1.2.3.4.5.6.7.8.9}
    
    // arr = [0 1 2 3 4 5 6 7 8 9]
    t.Log("arr = ", arr)

    s := arr[2:6]

    // before update s = [2 3 4 5], arr = [0 1 2 3 4 5 6 7 8 9]
    t.Logf("before update s = %v, arr = %v", s, arr)

    s[0] = Awesome!

    // after update s = [666 3 4 5], arr = [0 1 666 3 4 5 6 7 8 9]
    t.Logf("after update s = %v, arr = %v", s, arr)
}
Copy the code
  • Adding or deleting slice elements returns a new slice
func TestArrayAndSliceIncreasing(t *testing.T) {
    var s []int

    fmt.Println("add new item to slice")

    for i := 0; i < 10; i++ {
        s = append(s, i)

        fmt.Printf("s = %v, len(s) = %d, cap(s) = %d\n", s, len(s), cap(s))
    }

    fmt.Println("remove item from slice")

    for i := 0; i < 10; i++ {
        s = s[1:]

        fmt.Printf("s = %v, len(s) = %d, cap(s) = %d\n", s, len(s), cap(s))
    }
}
Copy the code
  • [index]Access slice elements only and slicelenAbout,[start:end]Create a new slice only with the original slicecapThe relevant
func TestArrayAndSliceBound(t *testing.T) {
    arr := [...]int{0.1.2.3.4.5.6.7.8.9}

    s1 := arr[5:8]

    // s1[0] = 5, s1[2] = 7
    t.Logf("s1[0] = %d, s1[%d] = %d", s1[0].len(s1)- 1, s1[len(s1)- 1])
    // s1 = [5 6 7], len(s1) = 3, cap(s1) = 5
    t.Logf("s1 = %v, len(s1) = %d, cap(s1) = %d", s1, len(s1), cap(s1))

    s2 := s1[3:5]

    // s2[0] = 8, s2[1] = 9
    t.Logf("s2[0] = %d, s2[%d] = %d", s2[0].len(s2)- 1, s2[len(s2)- 1])
    // s2 = [8 9], len(s2) = 2, cap(s2) = 2
    t.Logf("s2 = %v, len(s2) = %d, cap(s2) = %d", s2, len(s2), cap(s2))
}
Copy the code
  • onlymapThere is noset
func TestMapAndSet(t *testing.T) {
    m := map[string]string{
        "name": "snowdreams1006"."site": "https://snowdreams1006.github.io"."lang": "go",}// https://snowdreams1006.github.io
    if site, ok := m["site"]; ok {
        t.Log(site)
    } else {
        t.Log("site does not exist ")
    }

    s := map[string]bool{
        "name": true."site": true."lang": true,}// Pay attention to snowdreams1006
    if _, ok := m["isFollower"]; ok {
        t.Log("Have an eye on snowdreams1006")}else {
        s["isFollower"] = true
        t.Log("Pay attention to snowdreams1006")}}Copy the code
  • deleteFunction delete collectionmapKey/value pair
func TestMapAndSetByDelete(t *testing.T) {
    m := map[string]string{
        "name": "snowdreams1006"."site": "https://snowdreams1006.github.io"."lang": "go",}delete(m, "lang")

    // delete lang successfully
    if _,ok := m["lang"]; ! ok{ t.Log("delete lang successfully")}}Copy the code

What about the built-in containers in the Go language? If there is any wrong statement, please correct it. Welcome to come to the public account [Snow dream Technology Station] to learn and communicate, and make progress a little bit every day!