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

 约 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倍

数组跟切片的基本就到这了。还没有入门,学习中。有错误的地方欢迎指出。

bVbvvx4?w=258&h=258

阅读 517

推荐阅读
逸梦
用户专栏

一个PHP程序猿的文章栏目

17 人关注
49 篇文章
专栏主页
目录