• 第三章 内建容器 数组, 切片, map


    本章讲解了3方面的内容

    1. 数组

    2. 切片

    3. map


    一、数组

    1. 数组的定义方式

    var arr1 [5]int
    arr2 := [3]int{1, 3, 5}
    arr3 := [...]int{2, 4, 6, 8, 10}
    
    var grid [4][5]int
    
    fmt.Println(arr1, arr2, arr3)
    fmt.Println(grid)

    输出结果:

    [0 0 0 0 0] [1 3 5] [2 4 6 8 10]
    [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]

    2. 数组遍历的方式: 

    for i := 0; i < len(arr2); i++  {
        fmt.Println(arr2[i])
    }
    for i, v := range arr3 {
      fmt.Println(i, v)
    }        

    rang方式遍历的三种

    // 第一种: 只获取数组的下标
    for i := range arr3 {
        fmt.Println(arr3[i])
    }
    
    // 第二种: 获取数组的下标和值
    for i, v := range arr3 {
        fmt.Println(i, v)
    }
    
    // 第三种: 只获取值
    for _, v := range arr3 {
        fmt.Println(v)
    }

    3. arr[5] 和 arr[3]是不同的类型

    func printArray(arr [5]int) {
        arr[0] = 100
        for _, v := range arr {
            fmt.Println(v)
        }
    }
    
    func main() {
        var arr1 [5]int
        arr2 := [3]int{1, 3, 5}
        arr3 := [...]int{2, 4, 6, 8, 10}
    
        var grid [4][5]int
    
        fmt.Println(arr1, arr2, arr3)
        fmt.Println(grid)
    
        printArray(arr1)
        printArray(arr3)
        // 下面这个打印会报错, 因为arr2是3个容量的数组
        // printArray(arr2)
    }    

    这里传递arr1 和arr3过去的时候, 可以正常打印数组,但是传递arr2过去的时候, 会报异常. 

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

    原因是: [3]int 和[5]int是不同的类型

    4. 数组的传递是值拷贝类型. 

    func printArray(arr [5]int) {
        arr[0] = 100
        for _, v := range arr {
            fmt.Println(v)
        }
    }
    
    func main() {
        //定义数组的三种方法
        var arr1 [5]int
        arr2 := [3]int{1, 3, 5}
        arr3 := [...]int{2, 4, 6, 8, 10}
        // 证明数组是值拷贝类型
        fmt.Println("证明数组是值拷贝类型")
        printArray(arr1)
        printArray(arr3)
    
        fmt.Println(arr1, arr3)
    }

    我们在函数printArray中修改数组第一个元素的值是100. 然后打印. 在打印原数组. 结果如下:

    证明数组是值拷贝类型
    100
    0
    0
    0
    0
    100
    4
    6
    8
    10
    [0 0 0 0 0] [2 4 6 8 10]

    5. 如何实现数组的地址传递呢? 使用指针

    func printArray1(arr *[5]int) {
        arr[0] = 100
        for _, v := range arr {
            fmt.Println(v)
        }
    }
    
    func main() {
        //定义数组的三种方法
        var arr1 [5]int
        arr2 := [3]int{1, 3, 5}
        arr3 := [...]int{2, 4, 6, 8, 10}
        // 证明数组是值拷贝类型
        fmt.Println("如何让数组实现值拷贝呢")
        printArray(&arr1)
        fmt.Println(arr1)
    }

    结果

    如何让数组实现地址拷贝呢?
    100
    0
    0
    0
    0
    [100 0 0 0 0]

    注意: 

      a. 在方法printArray中参数接收是一个地址类型. 并且传递参数的时候也传递一个地址类型

      b. 在arr[0] = 100赋值的时候, 无需获取地址的值. 直接给指针类型的数组赋值即可

    二、切片slice

    1. 什么是slice

    func main() {
        // 定义一个数组
        arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
        fmt.Println("arr1[2:6] = ", arr1[2:6])
        fmt.Println("arr1[2:] = ", arr1[2:])
        fmt.Println("arr1[:6] = ", arr1[:6])
        fmt.Println("arr1[:] = ", arr1[:] )
    }

    结果

    arr1[2:6] =  [2 3 4 5]
    arr1[2:] =  [2 3 4 5 6 7]
    arr1[:6] =  [0 1 2 3 4 5]
    arr1[:] =  [0 1 2 3 4 5 6 7]

      a. 通过arr[a:b]方式获取的值就是slice

      b. slice是数组的一个视图. slice不是值传递的. slice内存储的是数组的地址

     2. 验证slice不是值传递

    func updateSlice(s []int) {
        s[0] =100
    }
    
    func main() {
        // 定义一个数组
        arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    
        s1 := arr1[2:]
        s2 := arr1[:]
        
        fmt.Println("after updateSlice(s1)")
        updateSlice(s1)
        fmt.Println(s1)
        updateSlice(s2)
        fmt.Println(s2)
        fmt.Println(arr1)
    }

    结果:

    after updateSlice(s1)
    s1 =  [100 3 4 5 6 7]
    s2 =  [100 1 100 3 4 5 6 7]
    arr1 =  [100 1 100 3 4 5 6 7]

    可以看到很有趣的现象. s1 的第一个元素被改100. 同时影响了s2的第3个元素. s2的第一个元素修改后,s1, s2同时都影响了数组arr1.

    由此可见: s1, s2 都是指向的数组的地址

    将s传递给函数printSlice, 在打印原来的s. 发现s的值变化了. 说明, 切片传递是地址传递, 而不是值传递. 

    可是上一章讲指针的时候,不是说go中只有值拷贝一种类型么? 那么为什么slice不是值拷贝呢? 因为slice是数组的一个视图. (可以理解为, 他取的是数组中指定元素的地址. 所以, slice不是值拷贝, 他的元素是地址)

     思考: 在上面将数组的第5个问题, 数组如何作为一个地址拷贝的方式作为参数传递到方法里面呢? 我们的做法是: 将数组作为一个指针传过去. 学习了slice,我们可以换一种方法.

    func printArray1(arr []int) {
        arr[0] = 100
        for _, v := range arr {
            fmt.Println(v)
        }
    }
    
    func main() {
    
        //定义数组的三种方法
        var arr1 [5]int
        arr2 := [3]int{1, 3, 5}
        arr3 := [...]int{2, 4, 6, 8, 10}
    
    
        fmt.Println(arr1, arr2, arr3)
    
        // 如何让数组实现地址拷贝呢?
        fmt.Println("如何让数组实现地址拷贝呢?方法2")
        printArray1(arr3[:])
        fmt.Println(arr3)
    }

    结果:

    [0 0 0 0 0] [1 3 5] [2 4 6 8 10]
    如何让数组实现地址拷贝呢?方法2
    100
    4
    6
    8
    10
    [100 4 6 8 10]
    1. printArray1(arr []int)接收参数的时候, 使用arr []int就是切片. 如果是arr [5]int就是数组.
    2.如何将一个数组传给接收切片的方法呢? 如下:
    printArray1(arr3[:])

    是不是很巧妙. 这种方法就不用使用& *了

    3. reslice

    我们对数组可以进行slice操作, 对slice还可以继续进行slice操作, 就是reslice

    package main
    
    import "fmt"
    
    func updateSlice(s []int) {
        s[0] =100
    }
    
    func main() {
        // 定义一个数组
        arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    
        s2 := arr1[:]
    
        fmt.Println("reslice操作")
        fmt.Println("slice 后: ", s2)
        s2 = s2[:5]
        fmt.Println("reslice 后: ", s2)
        s2 = s2[2:]
        fmt.Println("再次reslice 后: ", s2)
        updateSlice(s2)
        fmt.Println("再次reslice 然后修改第一个元素的值 后: ", s2)
        fmt.Println("原数组:", arr1)
    
    }

    输出结果:

    reslice操作
    slice 后:  [0 1 2 3 4 5 6 7]
    reslice 后:  [0 1 2 3 4]
    再次reslice 后:  [2 3 4]
    再次reslice 然后修改第一个元素的值 后:  [100 3 4]
    原数组: [0 1 100 3 4 5 6 7]

    我们看到对slice再次进行slice, 就和对数组slice是类似的. 最终指向的都是数组中的地址

    updateSlice(s2): 这个操作就比较有意思了. 我们看到, 对二次reslice后的数组,修改他的第一个元素的值. 然后在打印原数组,发现, 原数组的值也修改了. 再次证明, slice是数组的一个视图,最终存储的是数组的地址. 一旦被修改,会影响原数组.

    4. slice扩展

    看下面这个例子: 

    func main() {
        // 定义一个数组
        arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    
        s1 := arr1[2:6]
        s2 := s1[3:5]
    
        fmt.Println("s1 = ", s1, ", s2 = ", s2)
    
    }

    结果:

    s1 =  [2 3 4 5] , s2 =  [5 6]

    很奇怪: s1取的数组的4个元素. s2想要取s1的3-5个元素,可s1只有4个元素呀, s2还成功取出来了. 这是怎么回事呢?

    为什么会这样呢?我们来分析一下

     最开始, 数组中的值是0, 1, 2, 3, 4, 5, 6, 7

    当我们取s1切片的时候, s1是底层数组的一个视图, 他取值是从2-6, 虽然,他只取了4个元素,但是因为他是对底层的一个视图,所以他是可以看到底层后面的元素的.

    然后取s2切片. 我们发现他去的是s1下标的3-5个元素.  虽然s1只有4个元素, 因为他是可以看到底层其他后面的元素的, 所以, s2能够把数组中第5个元素取出来.

     那么取出来对应的元素值时多少呢?对应到底层数组, 他的值就是5和6

    那么s1只有4个元素, 为什么能够看到第五和第六个元素呢?

    原来slice的底层结构是这么定义的

     slice定义了3个对象.

    ptr是一个指针, 记录的是切片的第一个地址(下面的方格代表数组), 

    len是切片中元素的个数, 如果获取超过元素个数的值, 会报下标越界

    cap: 是capacity, 容量. 他存储的是从ptr指向的数组的元素开始, 一直到数组结束的元素.

    所以,s1[3:5]获取的是cap中的数据. 正常返回.

    总结: 1. slice 可以向后扩展, 但不能向前扩展. slice中cap的起始元素是从ptr开始

        2. s[i]不可以超越len(s), 向后扩展可以超越len(s),但不可以超过底层数组cap(t)

    5. 向slice添加元素

    package main
    
    import "fmt"
    
    func updateSlice(s []int) {
        s[0] =100
    }
    
    func main() {
        // 定义一个数组--为什么这样定义就能够被识别为一个数组呢
        arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    
        s1 := arr1[2:6]  // 2, 3, 4, 5
        s2 := s1[3:5]     // 4, 5
        fmt.Println("s2 = ", s2)
        fmt.Println("arr1 = ", arr1)
        s3 := append(s2, 10)    // 4, 5, 10
        fmt.Println("s3 = ", s3)
        fmt.Println("arr1 = ", arr1)
        s4 := append(s3, 11)    // 4, 5, 10 ,11
        fmt.Println("s4 = ", s4)
        fmt.Println("arr1 = ", arr1)
        s5 := append(s4, 12)    // 4, 5, 10 ,11, 12
        fmt.Println("s5 = ", s5)
        fmt.Println("arr1 = ", arr1)
        s6 := s5[2:5]
        fmt.Println("s6 = ", s6)
        updateSlice(s6)
        fmt.Println("arr1 = ", arr1)
    }

    结果

    s2 =  [5 6] ,              arr1 =  [0 1 2 3 4 5 6 7]
    s3 =  [5 6 10] ,           arr1 =  [0 1 2 3 4 5 6 10]
    s4 =  [5 6 10 11] ,        arr1 =  [0 1 2 3 4 5 6 10]
    s5 =  [5 6 10 11 12] ,     arr1 =  [0 1 2 3 4 5 6 10]
    s5 =  [100 6 10 11 12] ,   arr1 =  [0 1 2 3 4 5 6 10]

    添加元素是append. 那么我们来分析下这段代码:

    s2的值是5 ,6 原数组:[0 1 2 3 4 5 6 7]

    s3在s2基础上增加了元素10 , 我们发现原数组变为:[0 1 2 3 4 5 6 10]. 这说明, append也是对slice的cap进行处理的

    s4在s3基础上增加了元素11, 我们发现原数组较上一个没变化:[0 1 2 3 4 5 6 10]. 原因是什么呢?s4 增加的数组已经超过了cap范围, 这时会重新开辟一块新的空间. 因为这块空间已经保存不下这个数据了.

    s5的变化同s4, 虽增加了一个元素,但是, 原数组无变化

    s5第二次打印可以证明, 数组已经重新开辟了一块新的空间. 因为我对s5的第一个元素值进行了修改, 但修改后数组的值没有变化, 表明此时s5的切片指向的地址已经不是原来数组的地址了.

    下面来看看这几个元素的len 和cap是如何变化的

    package main
    
    import "fmt"
    
    func updateSlice(s []int) {
        s[0] =100
    }
    
    func main() {
        // 定义一个数组--为什么这样定义就能够被识别为一个数组呢
        arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    
        s1 := arr1[2:6]  // 2, 3, 4, 5
        s2 := s1[3:5]     // 4, 5
        fmt.Println("s2 = ", s2, ",             arr1 = ", arr1, ", len(s2)", len(s2), ", cap(s2)", cap(s2))
    
        s3 := append(s2, 10)    // 4, 5, 10
        fmt.Println("s3 = ", s3, ",        arr1 = ", arr1, ", len(s3)", len(s3), ", cap(s3)", cap(s3))
        s4 := append(s3, 11)    // 4, 5, 10 ,11
        fmt.Println("s4 = ", s4, ",        arr1 = ", arr1, ", len(s4)", len(s4), ", cap(s4)", cap(s4))
        s5 := append(s4, 12)    // 4, 5, 10 ,11, 12
        fmt.Println("s5 = ", s5, ",    arr1 = ", arr1, ", len(s5)", len(s5), ", cap(s5)", cap(s5))
        updateSlice(s5)
        fmt.Println("s5 = ", s5, ",arr1 = ", arr1, ", len(s5)", len(s5), ", cap(s5)", cap(s5))
    }

    打印结果:

    s2 =  [5 6] ,              arr1 =  [0 1 2 3 4 5 6 7]  ,len(s2) 2 ,cap(s2) 3
    s3 =  [5 6 10] ,           arr1 =  [0 1 2 3 4 5 6 10] ,len(s3) 3 ,cap(s3) 3
    s4 =  [5 6 10 11] ,        arr1 =  [0 1 2 3 4 5 6 10] ,len(s4) 4 ,cap(s4) 6
    s5 =  [5 6 10 11 12] ,     arr1 =  [0 1 2 3 4 5 6 10] ,len(s5) 5 ,cap(s5) 6
    s5 =  [100 6 10 11 12] ,   arr1 =  [0 1 2 3 4 5 6 10] ,len(s5) 5 ,cap(s5) 6    

    我们打印出了每一次变化后len的值和cap的值. 从s4开始, 增加了一个元素, 原来的地址已经容纳不了这么多数据了, 于是新开辟了一块空间. 元素的len是4, cap是当前数组的2倍. 已经不是原来的数组了

    总结:

    1. 添加元素时,如果超越capacity, 那么会重新开辟一块更大的底层数组, 把slice切片值copy过去. 原来的数组, 如果有人用就依然存在, 如果没人用就会被垃圾回收掉.

    2. 由于是值传递, 所以append必须要有一个返回值接收. 原因是: 当append的容量超过原来数组的时候, 会新开辟一块空间, 新开辟的空间需要有新的参数来接收.

    7.slice的copy

    package main
    
    import "fmt"
    
    func updateSlice(s []int) {
        s[0] =100
    }
    
    func printSlice(s []int) {
        fmt.Printf("len=%d, cap=%d 
    ", len(s), cap(s))
    }
    
    func main() {
    
        var sli []int // 这样定义就是一个zero value, 他的值时nil
    
        // 给sli赋值. 因为是zero value, 所以,可以直接复制
        for i := 0; i < 200 ;i ++  {
            printSlice(sli)
            sli = append(sli, 2*i+1)
        }
    }

    结果

    len=0, cap=0 
    len=1, cap=1 
    len=2, cap=2 
    len=3, cap=4 
    len=4, cap=4 
    len=5, cap=8 
    len=6, cap=8 
    len=7, cap=8 
    len=8, cap=8 
    len=9, cap=16 
    len=10, cap=16 
    len=11, cap=16 
    len=12, cap=16 
    len=13, cap=16 
    len=14, cap=16 
    len=15, cap=16 
    len=16, cap=16 
    len=17, cap=32 
    len=18, cap=32 
    len=19, cap=32 
    len=20, cap=32 
    len=21, cap=32 
    len=22, cap=32 
    len=23, cap=32 
    len=24, cap=32 
    len=25, cap=32 
    len=26, cap=32 
    len=27, cap=32 
    len=28, cap=32 
    len=29, cap=32 
    len=30, cap=32 
    len=31, cap=32 
    len=32, cap=32 
    len=33, cap=64 
    len=34, cap=64 
    len=35, cap=64 
    len=36, cap=64 
    len=37, cap=64 
    len=38, cap=64 
    len=39, cap=64 
    len=40, cap=64 
    len=41, cap=64 
    len=42, cap=64 
    len=43, cap=64 
    len=44, cap=64 
    len=45, cap=64 
    len=46, cap=64 
    len=47, cap=64 
    len=48, cap=64 
    len=49, cap=64 
    len=50, cap=64 
    len=51, cap=64 
    len=52, cap=64 
    len=53, cap=64 
    len=54, cap=64 
    len=55, cap=64 
    len=56, cap=64 
    len=57, cap=64 
    len=58, cap=64 
    len=59, cap=64 
    len=60, cap=64 
    len=61, cap=64 
    len=62, cap=64 
    len=63, cap=64 
    len=64, cap=64 
    len=65, cap=128 
    len=66, cap=128 
    len=67, cap=128 
    len=68, cap=128 
    len=69, cap=128 
    len=70, cap=128 
    len=71, cap=128 
    len=72, cap=128 
    len=73, cap=128 
    len=74, cap=128 
    len=75, cap=128 
    len=76, cap=128 
    len=77, cap=128 
    len=78, cap=128 
    len=79, cap=128 
    len=80, cap=128 
    len=81, cap=128 
    len=82, cap=128 
    len=83, cap=128 
    len=84, cap=128 
    len=85, cap=128 
    len=86, cap=128 
    len=87, cap=128 
    len=88, cap=128 
    len=89, cap=128 
    len=90, cap=128 
    len=91, cap=128 
    len=92, cap=128 
    len=93, cap=128 
    len=94, cap=128 
    len=95, cap=128 
    len=96, cap=128 
    len=97, cap=128 
    len=98, cap=128 
    len=99, cap=128 
    len=100, cap=128 
    len=101, cap=128 
    len=102, cap=128 
    len=103, cap=128 
    len=104, cap=128 
    len=105, cap=128 
    len=106, cap=128 
    len=107, cap=128 
    len=108, cap=128 
    len=109, cap=128 
    len=110, cap=128 
    len=111, cap=128 
    len=112, cap=128 
    len=113, cap=128 
    len=114, cap=128 
    len=115, cap=128 
    len=116, cap=128 
    len=117, cap=128 
    len=118, cap=128 
    len=119, cap=128 
    len=120, cap=128 
    len=121, cap=128 
    len=122, cap=128 
    len=123, cap=128 
    len=124, cap=128 
    len=125, cap=128 
    len=126, cap=128 
    len=127, cap=128 
    len=128, cap=128 
    len=129, cap=256 
    len=130, cap=256 
    len=131, cap=256 
    len=132, cap=256 
    len=133, cap=256 
    len=134, cap=256 
    len=135, cap=256 
    len=136, cap=256 
    len=137, cap=256 
    len=138, cap=256 
    len=139, cap=256 
    len=140, cap=256 
    len=141, cap=256 
    len=142, cap=256 
    len=143, cap=256 
    len=144, cap=256 
    len=145, cap=256 
    len=146, cap=256 
    len=147, cap=256 
    len=148, cap=256 
    len=149, cap=256 
    len=150, cap=256 
    len=151, cap=256 
    len=152, cap=256 
    len=153, cap=256 
    len=154, cap=256 
    len=155, cap=256 
    len=156, cap=256 
    len=157, cap=256 
    len=158, cap=256 
    len=159, cap=256 
    len=160, cap=256 
    len=161, cap=256 
    len=162, cap=256 
    len=163, cap=256 
    len=164, cap=256 
    len=165, cap=256 
    len=166, cap=256 
    len=167, cap=256 
    len=168, cap=256 
    len=169, cap=256 
    len=170, cap=256 
    len=171, cap=256 
    len=172, cap=256 
    len=173, cap=256 
    len=174, cap=256 
    len=175, cap=256 
    len=176, cap=256 
    len=177, cap=256 
    len=178, cap=256 
    len=179, cap=256 
    len=180, cap=256 
    len=181, cap=256 
    len=182, cap=256 
    len=183, cap=256 
    len=184, cap=256 
    len=185, cap=256 
    len=186, cap=256 
    len=187, cap=256 
    len=188, cap=256 
    len=189, cap=256 
    len=190, cap=256 
    len=191, cap=256 
    len=192, cap=256 
    len=193, cap=256 
    len=194, cap=256 
    len=195, cap=256 
    len=196, cap=256 
    len=197, cap=256 
    len=198, cap=256 
    len=199, cap=256 
    
    Process finished with exit code 0
    View Code

    从打印结果可以看出. 1) 没有个切片赋初始值, 他的默认长度是0 , 因此给切片append不会报错. 2) 每次cap容量不够的时候, 增长是按照当前元素值的2倍增长的.

    package main
    
    import "fmt"
    
    func updateSlice(s []int) {
        s[0] =100
    }
    
    func printSlice(s []int) {
        fmt.Printf("%v, len=%d, cap=%d 
    ", s, len(s), cap(s))
    }
    
    func main() {
    
        s1 := []int{1, 2, 3, 4}
        s2 := make([]int, 16)
        s3 := make([]int, 2)
    
        printSlice(s1)
        printSlice(s2)
        printSlice(s3)
    
        copy(s2, s1)
        printSlice(s2)
      
      copy(s3, s1)
      printSlice(s3)
    }

    结果:

    [1 2 3 4], len=4, cap=4 
    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16 
    [0 0], len=2, cap=2 
    [1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16 
    [1 2], len=2, cap=2 

    1) 定义切片可以使用的方法

    • var s1 []int. 初始值是nil, len是0 cap是0 ,可直接append
    • var s2 = []int{1, 2, 3, 4},有4个元素, len是4, cap是4
    • var s3 = make([]int, 16) , 有16个元素,初始值都是0 , len是16, cap是16. 

    2) copy是将s1 copy给s2.

    3) 如果, 目标容量小于原容量, 则只copy目标容量个数的值

    8. slice的delete

     slice不能直接delete, 也就是没有提供delete方法,那么如果想要删除中间的某一个元素, 怎么办呢?

    package main
    
    import "fmt"
    
    func updateSlice(s []int) {
        s[0] =100
    }
    
    func printSlice(s []int) {
        fmt.Printf("%v, len=%d, cap=%d 
    ", s, len(s), cap(s))
    }
    
    func main() {
        s1 := []int{1, 2, 3, 4}
        s2 := make([]int, 16)
        s3 := make([]int, 2)
    
        printSlice(s1)
        printSlice(s2)
        printSlice(s3)
    
        copy(s2, s1)
        printSlice(s2)
    
        fmt.Println("删除元素值4")
        s4 := append(s2[:3], s2[4:]...)
        printSlice(s4)
    
    }

    结果

    [1 2 3 4], len=4, cap=4 
    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16 
    [0 0], len=2, cap=2 
    [1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16 
    删除s2的元素值4
    [1 2 3 0 0 0 0 0 0 0 0 0 0 0 0], len=15, cap=16 

    s2的值是[1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16

    删除中间的元素4, 怎么操作呢? 使用s4 := append(s2[:3], s2[4:]...)

    注意:的一点是append的第二个参数是一个数组,而不是切片, 那么如何将切片转换为数组呢? 在切片后面加三个点...

    三、map

     map定义的三种方式

        // 第一种
        m := map[string]string {
            "aaa":"111",
            "bbb":"222",
            "ccc":"333",
            "ddd":"444",
        }
        
        // 第二种
        m1 := make(map[string]int)  // 使用make,创建了一个empty map
    
        // 第三种
        var m2 map[string]int         // 使用var, 创建了一个nil. nil和java中的null不同的是:nil可以参与运算.对null对象进行运算报异常
        fmt.Println(m, m1, m2)

    重点看一下第二种和第三种方式有何不同.

    方式二: 创建了一个empty map

    方式三: 创建了一个nil 的map

    虽然如此,二者都可以参与运算. go中的nil和java中的null不同的是: nil可以参与运算. 对null对象进行运算报异常

    二.循环遍历使用range

    //循环遍历
        for k, v := range m {
            fmt.Println(k, v) // map是无需的,每次输出可能不一样
        }

    三.判断key是否存在

        // 判断key是否存在
        if v, ok := m["aaa"]; ok {
            fmt.Println(v, ok)
        } else {
            fmt.Println(ok)
        }
    v, ok := m["aaa"]用来判断key是否存在

    四. 删除一个元素

    delete(m, "aaa")
  • 相关阅读:
    转《编程之美——微软技术面试心得》勘误表
    第一次 学习使用 智能指针
    test _todel
    (转 todo阅读)Android 官方博客 Android应用程序的内存分析(翻译)
    msdn snmp trap 研究可否 重入 转《Multiple Trap Registrations》
    wpbars在博客园开博客了
    创业失败的10个教训总结
    winform 的一种登录方法。
    快速建立Subversion
    (转)SQL Server 按某一字段分组取最大(小)值所在行的数据
  • 原文地址:https://www.cnblogs.com/ITPower/p/12251528.html
Copyright © 2020-2023  润新知