zoukankan      html  css  js  c++  java
  • Go数组和切片你不知道的区别

    开篇语

    数组和切片是两种不同的数据结构,比较常见,在Go语言中同时存在,今天我们就一起来看看他们在使用方式上,原理上的一些区别?

    数组

    在Go语言中,数组是一种具有相同类型固定大小的一种数据结构。

    我们先来看看数组的使用,数组类型声明时的方式是 []T ,前面的[]指定数组的大小,T指定数组的类型,如下我们声明了一下数组,数组的大小是3,在没指定数组初始值时数组默认初始值是{0,0,0}

    array1 := [3]int{}
    //我们可以通过如下方式给数组赋值
    array1[0] = 1
    array1[1] = 2
    array1[2] = 3
    //下面这种也是数组声明的一种方式,并且初始化数组的值为{1,2}
    array2 := [2]int {1,2}
    

    思考一下前面我们array1赋值给array2对吗?记住,这种方式是错误的,在Go语言中只有大小相等,类型相同的数组才是同类型的数组,之间才可以相互赋值,如下截图,我们可以看见array1赋值给array2时编译器报错

    array2 = array1
    

    看上面的图,我们再思考一个问题,我们把array3 赋值给array2后,修改了array3下标为0的值等于6,请问打印的结果是?这个问题考验的是我们把array3赋值给array2后,修改了array3的值,会对array2产生影响吗?答案是不会,记住,在Go中,数组属于基本类型,他们之间的赋值,传递是属于值拷贝,同样的,如果将数组作为参数在函数间传递,也是属于值拷贝

    第一种结果:0,0,0;  4,5; 6,5
    第二种结果:0,0,0;  6,5; 6,5
    
    

    数组的长度,我们声明了一个数组,那如何获取数组的长度呢?通过len(array4)获取数组的长度

    array4 := [2]int {1,2}
    l := len(array4)
    fmt.Println(""l)
    

    多维数组的声明,多为数组可以想象成就是多个一维数组,如下声明了一个二维数组,代表有两个一维数组,每个一维数组的长度是2

    array4 := [2][2]int{}
    array6 := [2][2]int{{1,2},{3,4}}
    

    对数组的访问和遍历

    //访问数组中的元素
    array4 := [2]int {1,2}
    //访问数组下标为0处的值并打印
    fmt.Println(array4[0])
    //通过range遍历数组,
    //i代表数组的下标,
    //v代表数组下标为i处的值
    for i,v := range array4{
        fmt.Println(i,v)
    }    
    array5 := [2][2]int{{1,2},{3,4}}
    for i,tempArray := range array5{
        //此时tempArray是一维数组
        //再通过range 遍历tempArrayy一维数组
        for j,v := range tempArray{
            fmt.Println(j,v)
        }
    }
    

    切片

    在Go语言中,切片是数组的一种高级运用,相对于数组,切片是一种更加方便,灵活,高效的数据结构。,切片并不存储任何元素而只是对现有数组的引用(不是值拷贝,是指针)

    切片的声明方式有以下几种

    通过数组创建一个切片

    array1 := [3]int{1,2,3}
    //将数组下标从1处到下标2处的元素转换为一个切片(前闭后开)
    slice1 := array1[1:2]
    

    直接声明一个切片

    //下面代码直接出初始化一个切片 (这里大家有个疑问,我不管怎么看都觉得它是一个数组啊)
    //记住,再go语言中,区别一个变量是数组还是切片,就看有没有定义长度
    //有定义长度就是数组,如array1,没定义就是切片 如slice2
    //我们也通过fmt.Println(reflect.TypeOf(array1),reflect.TypeOf(slice2))
    //上面这代码打印的结果是[3]int,[]int,可以看到前者有长度,后者没有
    slice2 := []int{1,2,3}
    

    通过make函数创建一个切片,也是最常用的

    //[]int,指定切片的类型,3是切片的长度,6是切片的容量
    slice3 := make([]int,3,6)
    

    通过切片生成一个切片

    //声明一个切片
    slice4 := []int {1,2,3,4,5,6}
    //通过slice4创建一个切片,元素是slice4下标从0到1(不包含1)的元素
    slice5 := slice4[0:1] 
    //通过slice4创建一个切片,元素是slice4下标从0到末尾的元素
    slice6 := slice4[1:] 
     //通过slice4创建一个切片,元素是slice4下标从0到3的元素
    slice7 := slice4[:3]
    

    上面我们介绍了切片的几种常见构造方式,接下来我们看看如何操作切片

    slice3   := make([]int,3,6)
    //给切片赋值
    slice3[0] = 0
    slice3[1] = 1
    slice3[2] = 2
    //通过len([]Type) cap([]Type)两个函数查看切片的长度和容量
    fmt.Println(len(slice3),cap(slice3))
    结果:3,6
    

    思考一下我们能给上面切片slice3下标为3处赋值吗 ? slice3[3] = 3,答案是不能的,虽然我们定义了切片的长度是3,容量是6,但对切片的操作是以长度为准的,如果已经赋值到最大长度了,怎么办呢?切片为我们提供了append([]Type, elems...Type)[]Type 方法向切片中追加元素 []Type代表传入一个切片,elems代表追加的元素,可以传多个。

    //想slice3 切片追加三个元素,返回一个新的切片
    slice3 = append(slice3,3,4,5)
    //此时再次查看切片的长度和容量
    fmt.Println(len(slice3),cap(slice3))
    结果: 6, 6 切片的长度和容量保持一致了
    //思考一下,我们再次append能给切片追加元素吗? 肯定可以的,前面说过切片是可扩长的
    slice3 = append(slice3,7,8,9)
    //此时再次查看切片的长度和容量
    fmt.Println(len(slice3),cap(slice3))
    结果:9, 12
    发现了什么?在切片容量满时,切片的扩容时翻倍的,也就是新的切片的容量时原切片的容量的2倍
    

    知道了切片的追加,长度,容量,那么如何删除切片里的元素呢?如果你在看通过切片创建一个切片时思考过,你就知道如何删除切片中的元素了

    //我们创建了一个切片,有四个元素,下标命名为0,1,2,3
    slice11 := []int{1,2,3,4} 
    //假设我们要删除下标为0的元素,这段代码的含义是
    创建一个空的切片 slice11[:0]
    创建一个从下标1到末尾元素的切片 slice11[1:]
    给空切片添加元素并返回一个新的切片
    slice12 := append(slice11[:0],slice11[1:]...)
    //同上我们得出删除下标为i的元素的切片的公式时
    sliceTemp := append(slice11[:i],slice[i+1:]...)
    

    下图是切片删除的一个过程

    数组和切片的底层存储

    我们看下图分析

    基于上图我们会发现,切片的底层就是数组,切片是通过指针的形式指向不同数组的位置从而形成不同的切片,切片对本身元素的修改,也会影响到数组和其它的切片。看下面代码,大家猜一猜输出结果

    array11 := [5]int{1,2,3,4,5}
    slice11 := array11[0:3]
    slice11[0] = 10
    sliceTemp := append(array11[:2],array11[3:]...)
    slice11[0] = 11
    fmt.Println(array11,slice11,sliceTemp)
    //输出结果:[11 2 4 5 5] [11 2 4] [11 2 4 5]
    

    欢迎大家关注微信公众号:“技术人技术事”,更多精彩期待你的到来

    ![](https://img2018.cnblogs.com/blog/706455/201908/706455-20190821135940196-775543041.jpg)

    ,
  • 相关阅读:
    Educational Codeforces Round 86 (Rated for Div. 2) D. Multiple Testcases
    Educational Codeforces Round 86 (Rated for Div. 2) C. Yet Another Counting Problem
    HDU
    HDU
    HDU
    HDU
    Good Bye 2019 C. Make Good (异或的使用)
    Educational Codeforces Round 78 (Rated for Div. 2) C. Berry Jam
    codeforces 909C. Python Indentation
    codeforces1054 C. Candies Distribution
  • 原文地址:https://www.cnblogs.com/sy270321/p/11388399.html
Copyright © 2011-2022 走看看