go study notes the array or slice are no different

Last article details the Gobasis of language, pointed Goand differences other mainstream programming languages, more focused on the details of grammar, I believe that with a little memory can easily switch from an existing programming language to Goprogramming language customary in , although the switch may not be particularly smooth, but especially a lot of trial and error practice more, always can slowly feel the Gobeauty of the language!

In the study Gobefore the built-in container, the same, we briefly review the Gobasic language, with knowledge of the new temperature can serve as a teacher!

Review section on knowledge

For more information, please micro-channel public number [Snow Dream Inn technology] to see inside go study notes the particular concern of what basic grammar article, feel useful, easily forwarded chant!

Built-in type species

  • bool

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

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

2^0=1, 2^1=2, 2^2=4A byte integer length, and comprising a signed integer, and unsigned integer uintptrtype of pointer type, the default value is initialized to zero 0.

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

byteIt is the most basic byte type is the uint8type of alias , and runeis Gothe character type, is int32an alias. The most common type string stringshould not have introduced it?

  • float32 ,float64 ,complex64 ,complex128

Only floattype float, no doubletype, to distinguish the same length in bytes, complex64it is a complex type, the real and imaginary parts of a float32complex type made, thus writing complex64this form.

Features built-in type

  • Only display conversion type conversion, there is no form of implicit type conversions

Not automatically implicit type conversions between different types of variable Gotype conversion is only mandatory language, can only display conversion.

  • While providing the type of pointer, but the pointer itself can not carry out any form of computing.

Pointer type variables can not be calculated, but can be re-directed to change the memory address.

  • After the declaration of a variable is initialized with a default value of zero, zero value variable depending on the specific on the type of

intZero value type of a variable is initialized 0, stringzero value type is initialized to an empty string, notnil

Basic operators

  • No arithmetic operators ++iand--i

Only i++, and i--this increment operator, no longer have to worry about the differences of the two ways!

  • Comparison operators ==can compare arrays for equality

When the values of the array length and dimensions of the two arrays, two arrays can be compared, when exactly the same order, as a result true, otherwise it is false.

  • Bitwise Operators Bitwise new operator clears &^

Other mainstream programming language, although there is no such operator, the command can also be achieved by combining similar functions, but since it provides a bit is cleared by the operator, no longer have to conduct their own combination using!

Flow control statements

  • if The conditional expression does not need parentheses and support for variable assignment

Define temporary variables and variable according to the logic, then classification process according to different situations, Gohandling of such temporary variables, conditional expressions directly enhanced, this situation will be very common in the future!

  • if Variables defined in the conditional expression scope is limited to the current statement block

Variables defined in the conditional expression is to facilitate the different branches of the processing logic, since it is a temporary variable, a current ifblock of statements can not be used, it becomes possible to understand.

  • switchStatement can not break, unless thefallthrough

switchMultiple statements caseat the end can not break, the system will automatically breakprocess.

  • switch The conditional expression is not limited to a constant integer or

And compared to other mainstream programming language, Gothe language of switchthe conditional expression is more powerful, but also more relaxed type.

  • switchThe conditional expression may be omitted, the steering branching logic caselanguage.

Omitting switchthe conditional expression, a plurality of caselanguage branching process control, multi-function and effect if elsethe same.

  • Omitting switchthe conditional expression, for each casecondition may have multiple conditions, separated by commas.

swicthThe statement is essentially the corresponding flow control according to different conditions, each caseconditional expression to support multiple, but also enhances the ability of process control.

  • for Conditional expressions cycle does not need parentheses, and no other form of circulation.

GoLanguage only forcycle, no whileother form of circulation.

  • for The initial condition for the loop termination condition expressions, and self-energizing may be omitted while omitting or

After the conditional expression can be omitted to achieve whilethe effect of the cycle, all omitted, is an endless loop.

Function and parameter passing

  • Function declaration in accordance with the function name, into the reference, the reference sequence is defined, and supports multiple return values

Whether variable definition or function definition, Goalways and other mainstream programming language to the opposite of, if I can think of in the order of input and output will find that this definition is actually quite justified way.

  • Function has multiple return values ​​can be named to the return value, but there is no difference in terms of the caller

You may have a function return multiple values ​​variable names to facilitate the call to quickly see the familiar function declaration name known meaning, but the caller does not have to call to receive the return value in accordance with the result of the name.

  • Into the reference function is not complicated concepts required parameters, optional parameters, only supports variable argument lists

Variable parameter lists and other mainstream programming languages, must be the last one into the argument.

  • Passing arguments to functions only transfer value, no reference is transmitted, i.e., all variables need to copy

Only the parameter values ​​are passed passed, more simple logic, but can be passed to achieve the effect of passing a pointer references dealing with complex situations.

What are built container

Reviewed Gothe basic grammar of the language, we began to continue learning variable type of knowledge that is the bearer of the container.

Carrying a class of the most basic underlying variable is an array of containers, the most senior of the container bottom can rely array package, we first look at Gothe array What is the difference?

Arrays and slices

  • Declare and initialize an array

Distinctive features of the array is at the same time the length of the statement of contiguous memory a set of specific length, when declaring an array must specify the array can be initialized, of course, when you do not specify the array length can also use the ...syntax for the compiler to 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 0 0]]
    t.Log(grid)
}

[3]intSpecified array length 3, element type int, of course, can also directly assign declaration [5]int{1, 2, 3, 4, 5}, if bother specified array length, it can be [...]int{2, 4, 6, 8, 10}expressed.

  • And traverse the elements of the array access

The most common forloop traverse is accessed according to the index of the array, range arrthe way 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)
    }
}

range arrCan return to the index value and the index entries, if only care about the index entry and do not care about the value of the index, you can use _placeholder represents the index value is ignored, if only care about the value of the index, you can not write index entry. This is the function of the processing logic multi sequentially receives the return value, unused variables may not appear.

  • Array is a value type can be compared

An array is a value type, this and other mainstream programming languages ​​are different, so the same latitude and same number of elements in the array can be compared, in front of the contents in this regard has also been emphasized here again briefly recall.

func printArray(arr [5]int) {
    arr[0] = 666
    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)
}

Because the parameter passed is passed by value, so the printArrayfunction can not change the external value of the function caller passed, if you want to function in printArrayan array of content delivery over internal changes can be achieved through a pointer, but is there a more simple way?

Want to printArrayByPointermodify the parameter array inside the function, array pointer by the way, if there are not familiar with the place, you can look to see the review article.

func printArrayByPointer(arr *[5]int) {
    arr[0] = 666
    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)
}

Modify elements of the array may be achieved by passing an array of pointers, in addition, Gothe language there is a close relative of the array slice, i.e. the slice, it can achieve a similar effect.

  • Slice the declaration and initialization

Slice and arrays are very similar, if not the length of the array is created when the array is specified, then the final slice is not actually created 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))
}

[]intLength is not specified, this time slice is created, the default value of zero initialization is nilnot empty array!

Similarly, you can declare and initialize an array, can be sliced, and the syntax is very similar, little attention thought it was an array of it!

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)
}

Just do not specify the []length, the final result was created to become a slice, really dazzling!

Arrays and slices so similar, people have suspected what shady dealings between the two can actually get a slice from an array, the following are examples?:

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[:])
}

arr[start:end] The results obtained by the interception of a part of the array is the slice, slice concept is very vivid ah!

And other mainstream programming languages, [start:end]is a closed left and right open interval, sliced meaning is very clear:

Ignore the starting index start, the arr[:end]representation from the beginning until the termination of the original array index endbefore one;
ignored termination index end, the arr[ start:]representation from the original array starting index startstart until the last bit;
both ignore the starting index and ignoring the termination of the index, although less common but should be is on the meaning of the original array, but remember that the type is not an array slice yo!

So far, we know that is very similar to an array of slices and slice relative to the size of the array is not only, as it does it on a slice operation and arrays?

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

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)
}

Things can actually change the slice to pass parameters, but this is not done array of ah! Unless the array pointer type, slice was able to easily do? Unless it is inside a slice pointer, because the parameters passed only value is passed, there is no way passed by reference !

Slice and array performance parameters passed in a different, specific performance can not be modified when the array is an array parameter passing, you want to pass an array only want to change the array pointer for the job and has achieved a slice of the array change!

Since the parameter values ​​are passed pass only one way, it is presumed that there is certainly inside the slice pointer, parameter passing is passed a pointer, the internal function of changes can affect the function of the external variables.

go-container-about-slice-struct.png

sliceThere are three implementations of internal variables, pointers ptr, the number lenand capacity cap, which ptrpoints to the actual data storage addresses.

It is because of this slice internal implementation requires characteristic manifestations worth mentioning Ye Hao makes switches and arrays are inextricably linked, in fact, this data is the result of an extension of static arrays, in essence, is a dynamic array only, but the Golanguage is called a slice !

Slice is a dynamic array, it is easy to explain the above problem, the transmission parameter is an internal pointer passed, and thus the value passed though a copy pointer, but the pointer to the real elements, after all, is the same, so that the slice value of the external parameters can be modified .

Arrays can be compared to a certain extent, is a dynamic array slice, can not be compared to? Let the following test methods to verify your guess now!

go-container-about-slice-compare.png

不知道你有没有猜对呢?切片并不能进行比较,只能与 nil 进行判断.

  • 切片的添加和删除

数组是静态结构,数组的大小不能扩容或缩容,这种数据结构并不能满足元素个数不确定场景,因而才出现动态数组这种切片,接下来重点看下切片怎么添加或删除元素.

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)
}

添加元素 s = append(s, i) 需要扩容时,每次以 2 倍进行扩容,删除元素 s[1:] 时,递减缩容.

s = append(s, i) 向切片中添加元素并返回新切片,由于切片是动态数组,当切片内部的数组长度不够时会自动扩容以容纳新数组,扩容前后的内部数组会进行元素拷贝过程,所以 append 会返回新的地址,扩容后的地址并不是原来地址,所以需要用变量接收添加后的切片.

当不断进行切片重新截取时 s[1:] ,切片存储的元素开始缩减,个数递减,容量也递减.

go-container-about-slice-add-and-delete.png

其实除了基于数组创建切片和直接创建切片的方式外,还存在第三种创建切片的方式,也是使用比较多的方式,那就是 make 函数.

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))
}

通过 make 方式可以设置初始化长度和容量,这是字面量创建切片所不具备的能力,并且这种方式创建的切片还支持批量拷贝功能!

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))
}

func copy(dst, src []Type) int 是切片之间拷贝的函数,神奇的是,只有目标切片是 make 方式创建的切片才能进行拷贝,不明所以,有了解的小伙伴还请指点一二!

切片的底层结构是动态数组,如果切片是基于数组截取而成,那么此时的切片从效果上来看,切片就是原数组的一个视图,对切片的任何操作都会反映到原数组上,这也是很好理解的.

那如果对切片再次切片呢,或者说切片会不会越界,其实都比较简单了,还是稍微演示一下,重点就是动态数组的底层结构.

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))
}

[] 只能访问 len(arr) 范围内的元素,[:] 只能访问 cap(arr) 范围内的元素,一般而言 cap >= len 所以某些情况看起来越界,其实并不没有越界,只是二者的标准不同!

我们知道切片 slice 的内部数据结构是基于动态数组,存在三个重要的变量,分别是指针 ptr,个数 len 和容量 cap ,理解了这三个变量如何实现动态数组就不会掉进切片的坑了!

个数 len 是通过下标访问时的有效范围,超过 len 后会报越界错误,而容量 cap 是往后能看到的最大范围,动态数组的本质也是控制这两个变量实现有效数组的访问.

go-container-about-slice-outOfBound-len.png

因为 s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 6 ,所以 [] 访问切片 s1 元素的范围是[0,4) ,因此最大可访问到s1[3],而 s1[4] 已经越界了!

go-container-about-slice-outOfBound-cap.png

因为 s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 6 ,所以 [:] 根据切片 s1 创建新切片的范围是 [0,6] ,因此最大可访问范围是 s1[0:6] ,而 s1[3:7] 已经越界!

集合 map

集合是一种键值对组成的数据结构,其他的主流编程语言也有类似概念,相比之下,Go 语言的 map 能装载的数据类型更加多样化.

  • 字面量创建 map 换行需保留逗号 ,
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)
}

一对键值对的结尾处加上逗号 , 可以理解,但是最后一个也要有逗号这就让我无法理解了,Why ?

  • make 创建的 map 和字面量创建的 map 默认初始化零值不同
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)
}

make 函数创建的 map 是空 map,而通过字面量形式创建的 mapnil,同样的规律也适合于切片 slice.

  • range 遍历 map 是无序的
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)
    }
}

这里再一次遇到 range 形式的遍历,忽略键或值时用 _ 占位,也是和数组,切片的把遍历方式一样,唯一的差别就是 map 没有索引,遍历结果也是无序的!

  • 获取元素时需判断元素是否存在
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 ")
    }
}

Go 语言的 map 获取不存在的键时,返回的是值对应类型的零值,map[string]string 返回的默认零值就是空字符串,由于不会报错进行强提醒,这也就要求我们调用时多做一步检查.当键值对存在时,第二个返回值返回 true,不存在时返回 false.

  • 删除键值对时用 delete 函数
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)
}

delete(map,key) 用于删除 map 的键值对,如果想要验证是否删除成功,别忘了使用 value,ok := m[k] 确定是否存在指定键值对

  • slice,map,func 外,其余类型均可键

因为 map 是基于哈希表实现,所以遍历是无序的,另一方面因为 slice,map,func 不可比较,因为也不能作为键.当然若自定义类型 struc 不包含上述类型,也可以作为键,并不要求实现 hashcodeequal 之类的.

  • value 可以承载函数 func 类型
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 4 27
    t.Log(m[1](1), m[2](2), m[3](3))
}

再一次说明函数是一等公民,这部分会在以后的函数式编程中进行详细介绍.

没有 set

Go 的默认类型竟然没有 set 这种数据结构,这在主流的编程语言中算是特别的存在了!

正如 Go 的循环仅支持 for 循环一样,没有 while 循环一样可以玩出 while 循环的效果,靠的就是增强的 for 能力.

所以,即使没有 set 类型,基于现有的数据结构一样能实现 set 效果,当然直接用 map 就可以封装成 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)
}

使用 map[type]bool 封装实现 set 禁止重复性元素的特性,等到讲解到面向对象部分再好好封装,这里仅仅列出核心结构.

知识点总结梳理

Go 语言是十分简洁的,不论是基础语法还是这一节的内建容器都很好的体现了这一点.

数组作为各个编程语言的基础数据结构,Go 语言和其他主流的编程语言相比没有什么不同,都是一片连续的存储空间,不同之处是数组是值类型,所以也是可以进行比较的.

这并不是新鲜知识,毕竟上一节内容已经详细阐述过该内容,这一节的重点是数组的衍生版切片 slice .

因为数组本身是特定长度的连续空间,因为是不可变的,其他主流的编程语言中有相应的解决方案,其中就有不少数据结构的底层是基于数组实现的,Go 语言的 slice 也是如此,因此个人心底里更愿意称其为动态数组!

切片 slice 的设计思路非常简单,内部包括三个重要变量,包括数组指针 ptr,可访问元素长度 len 以及已分配容量 cap .

When continually adding new elements into slices, has always reached the maximum capacity allocated, then it will automatically sliced ​​expansion, otherwise it will volume reduction, enabling the ability to dynamically control!

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

    // [0 0 0] []
    t.Log(arr1,arr2)
}
  • Based slice array creation 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] = 666

    // 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)
}
  • Add or delete elements return the new slice sliced
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))
    }
}
  • [index]Access slice and slice the only elements lenrelated to [start:end]creating a new and original slice sliced just capabout
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))
}
  • Only mapnoset
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")
    }
}
  • deleteFunction deletes the set mapkey-value pairs
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")
    }
}

About Golanguages have built-in container is not Getit? If you have a place to express wrong, please correct me ha, welcome to take a public number [Snow Dream Inn technologies] learning exchanges, a little progress every day!

Snow Dream Inn technology .png

Guess you like

Origin www.cnblogs.com/snowdreams1006/p/11374595.html