golang学习笔记切片slice-与数组-arr

16次阅读

共计 2075 个字符,预计需要花费 6 分钟才能阅读完成。

因为我是写 php 的,刚开始写 go 的时候老是被数组坑。因为在 go 中的数组是固定长度,所以会存在越界的时候。而在 go 中也很少直接使用数组。更多的时候会使用slice(切片)。

数组

数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。数组的长度是固定的。和数组对应的类型是 Slice(切片),它是可以增长和收缩动态序列,slice 功能也更灵活,但是要理解 slice 工作原理的话需要先理解数组。

数组的声明, 需要指出数组内部元素类型,以及数组的长度

var  name [len]type

如:声明一个长度为 5 的 Int 类型数组

var numbers [5]int

数组元素的访问也是跟大多数语言一样,可以通过索引下标来访问,索引下标的范围是从 0 开始到数组长度减 1 的位置。内置的 len 函数将返回数组中元素的个数。
下面是一些数组的简单操作

func main() {var arr [3]int // 声明一个长度为 3 的数组
    // 往数组中增加元素
    arr[0] = 1
    arr[1] = 2
    arr[2] = 3
    // arr[3] = 1  这里就会产生错误

    // 在声明数组的时候复制
    var addArr = [3]int{1, 2, 3}
    fmt.Println(addArr[0]) //

    moreArr := [...]int{1, 2} // 这里... 表示不确定长度。最终数组的长度由实际的元素个数确认
    fmt.Println(moreArr[0])   //

    // 数组的使用
    for k, v := range arr {fmt.Printf("第 %d 个元素为 %d\n", k+1, v)
    }

}

切片

slice 是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,slice 的底层引用了一个数组对象。一个 slice 由三个部分构成:指针、长度和容量。指针指向第一个 slice 元素对应的底层数组元素的地址,要注意的是 slice 的第一个元素并不一定就是数组的第一个元素。长度对应 slice 中元素的数目;长度不能超过容量,容量一般是从 slice 的开始位置到底层数据的结尾位置。

func main() {arr := [5]int{1, 2, 3, 4, 5} // 定义一个数组
    sle1 := arr[0:2]             // 切片 1
    sle2 := arr[1:3]             // 切片 2
    sle1[0] = 9                  // 现在改变第一个切片的第一个元素
    fmt.Println(arr)             //[9 2 3 4 5]
    fmt.Println(sle1)            //[9 2]
    fmt.Println(sle2)            //[2 3]

    /**
     * 现在改变两个切片共有的元素,通过结果可以看到
     * 底层数组 以及 sle2 中的一个元素都以及被改变了。* 可以很好的说明 切片是对数组的引用。两个切片实际引用的是同一个底层数组
     *
     */
    sle1[1] = 10

    fmt.Println(arr)  //[9 10 3 4 5]
    fmt.Println(sle1) //[9 10]
    fmt.Println(sle2) //[10 3]

}

上面的例子说明切片的第一个构成部分是指向底层数组的指针,下面来看看容量跟长度。
内置的 len 和 cap 函数分别返回 slice 的长度和容量。

func main() {arr := [5]int{1, 2, 3, 4, 5}
    sli := arr[:4] // [1,2]
    fmt.Printf("切片长度为 %d, 容量为 %d\n", len(sli), cap(sli))
   // 切片长度为 4, 容量为 5
    sl2 := arr[:2] // [1,2]
    fmt.Printf("切片长度为 %d, 容量为 %d\n", len(sl2), cap(sl2)) 
    // 切片长度为 2, 容量为 5

     sl3 := sli[:6] // 这里会产生 panic range of index。因为超过源切片的容量

}

这里我们可以看到,如果切片操作超出 cap(s)的上限将导致一个 panic 异常,但是超出 len(s)则是意味着扩展了 slice,因为新 slice 的长度会变大。那么我们应该怎么去给切片扩容呢,这里我们需要用到 append 方法、看下面的例子

func main() {
    /**
     * 这里使用 make 创建一个切片  
      * make([]T, len, cap) 其中 cap 可以省略。默认为 Len
     */
    sli := make([]int, 1, 1) 

    fmt.Printf("切片长度为 %d, 容量为 %d\n", len(sli), cap(sli)) //2
    for i := 1; i < 5; i++ {sli = append(sli, 2)
        fmt.Printf("切片长度为 %d, 容量为 %d\n", len(sli), cap(sli)) //2
    }

}
输出结果
切片长度为 1, 容量为 1, 地址为 0xc00005a420
切片长度为 2, 容量为 2, 地址为 0xc00005a420
切片长度为 3, 容量为 4, 地址为 0xc00005a420
切片长度为 4, 容量为 4, 地址为 0xc00005a420
切片长度为 5, 容量为 8, 地址为 0xc00005a420

通过上面例子可以看出,当切片长度大于当前容量的时候,会为当前切片自动扩容。每次扩容的大小为当前容量的 2 倍

数组跟切片的基本就到这了,下一篇我会写一些切片的应用。还没有入门,学习中。有错误的地方欢迎指出。

正文完
 0