golang数据类型-slice(切片)

JesseYoung · · 12439 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

slice介绍       数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。在初始定义数组时,我们并不知道需要多大的数组,因此我们就需要“动态数组”。在Go里面这种数据结构叫slice,slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度,它是可变长的,可以随时往slice里面加数据。     初看起来,数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构,而不仅仅是个指针。数组切片的数据结构可以抽象为以下3个变量:     1.一个指向原生数组的指针(point):指向数组中slice指定的开始位置;     2.数组切片中的元素个数(len):即slice的长度;     3.数组切片已分配的存储空间(cap):也就是slice开始位置到数组的最后位置的长度。     从底层实现的角度来看,数组切片实际上仍然使用数组来管理元素,基于数组,数组切片添加了一系列管理功能,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制。   slice声明       声明slice时方括号[]内没有任何数据     声明一个元素类型为int的slice     var mySlice []int    声明两个元素类型为byte的slice    
    var aSlice, bSlice []byte 
slice初始化    
    直接初始化(创建)    并非一定要事先准备一个数组才能创建数组切片。Go语言提供的内置函数make()可以用于灵活地创建数组切片。
    bSlice := {'a', 'b', 'c', 'd'} //直接创建并初始化包含4个元素的数组切片

    通过数组初始化(创建)
    var aSlice, bSlice, cSlice, dSlice []byte
    aSlice = arr[2:5] //aSlice包含元素: arr[2],arr[3]和arr[4]
    bSlice = arr[:5]  //aSlice包含元素: arr[0],arr[1],arr[2],arr[3]和arr[4]
    cSlice = arr[2:]  //aSlice包含元素: arr[2],arr[3]...arr[8]和arr[9]
    dSlice = arr[:]   //aSlice包含元素: arr[0],arr[1]...arr[8]和arr[9]
    注:slice通过array[first:last]来获取,其中first是数组的开始位置,last是结束位置,但不包含array[last],它的长度是last-first。
        slice的默认开始位置是0,arr[:n]等价于arr[0:n]
        slice的第二个序列默认是数组的长度,arr[n:]等价于arr[n:len(arr)]
        如果从一个数组里面直接获取slice,可以这样arr[:],因为默认第一个序列是0,第二个是数组的长度,即等价于arr[0:len(arr)]

    通过slice初始化(创建)
    var aSlice, bSlice []byte
    bSlice = aSlice[1:3]  //bSlice 包含aSlice[1], aSlice[2] 也就是含有: e,f
    bSlice = aSlice[:3]   //bSlice 包含 aSlice[0], aSlice[1], aSlice[2] 也就是含有: d,e,f
    bSlice = aSlice[0:5]  //对slice的slice可以在cap范围内扩展,此时bSlice包含:d,e,f,g,h
    bSlice = aSlice[:]    //bSlice包含所有aSlice的元素: d,e,f,g
    Slice_a := Array_a[2:5]
        fmt.Println("mySlice[", i, "] =", v)
    }
元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相当于把mySlice2包含的所有元素打散后传入。
    aSlice := []int{1, 2, 3, 4, 5}
    bSlice := []int{5, 4, 3}
    copy(bSlice, aSlice) // 只会复制aSlice的前3个元素到bSlice中
    copy(aSlice, bSlice) // 只会复制bSlice的3个元素到aSlice的前3个位置
    slice1 := copy(s, a[:])         //说明:把a 全部的值复制到s 中
    slice2 := copy(s, a[2:])        //说明:把指定范围的值复制到s 的开始位置
    slice3 := copy(s[4:6], a[6:8])  //说明:把指定范围的值复制到s 的指定位置
    var mySlice []int
    aSlice:= {1,2,3,4,5}           //直接创建并初始化包含4个元素的数组切片
    cSlice := make([]int, 5)       //创建一个初始元素个数为5的整型数组切片,元素初始值为0
    dSlice := make([]int, 5, 10)   //创建一个初始元素个数为5的整型数组切片,元素初始值为0,并预留10个元素的存储空间
    
    数组切片可以基于一个已存在的数组创建。数组切片可以只使用数组的一部分元素或者整个数组来创建,甚至可以创建一个比所基于的数组切片(而非数组)还要大的数组切片。
    arr := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
        aSlice元素范围甚至可以超过所包含的元素个数,比如bSlice可以基于aSlice的前4个元素创建,虽然aSlice只包含3个元素。只要这个选择的范围不超过aSlice存储能力(即cap()返回的值8),那么这个创建程序就是合法的。bSlice中超出aSlice元素的部分都会填上0。
    例如:
    Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
    上面代码的真正存储结构如下图所示:
    
    注:slice是引用类型,所以当引用改变其中元素的值时,其它的所有引用都会改变该值,例如上面的aSlice和bSlice,如果修改了aSlice中元素的值,那么bSlice相对应的值也会改变。
slice元素遍历(range)
    操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len()函数获取元素个数,并支持使用range关键字来快速遍历所有元素。
    使用range关键字可以让遍历代码显得更整洁。range表达式有两个返回值,第一个是索引,第二个是元素的值:
    for i, v := range mySlice {
slice元素动态增减(append)
    可动态增减元素是数组切片比数组更为强大的功能。与数组相比,数组切片多了一个存储能力(capacity)的概念,即元素个数和分配的空间可以是两个不同的值。合理地设置存储能力的值,可以大幅降低数组切片内部重新分配内存和搬送内存块的频率,从而大大提高程序性能。
    数组切片支持Go语言内置的cap()函数和len()函数,cap()函数返回的是数组切片分配的空间大小,而len()函数返回的是数组切片中当前所存储的元素个数。
    append:向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slice
    例如:
    aSlice := make([]int, 5, 10)
    aSlice = append(aSlice, 1,2,3)  //从尾端给aSlice加上3个元素,从而生成一个新的数组切片,函数append()的第二个参数其实是一个不定参数,我们可以按自己需求添加若干个元素
    可以直接将一个数组切片追加到另一个数组切片的末尾,如:
    bSlice := []int{4, 5, 6}
    aSlice = append(aSlice, bSlice...) //等同于aSlice = append(aSlice, 4, 5, 6)
    注:第二个参数mySlice2后面加了三个点,即一个省略号,如果没有这个省略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的
        数组切片会自动处理存储空间不足的问题。如果追加的内容长度超过当前已分配的存储空间(即cap()调用返回的信息),数组切片会自动分配一块足够大的内存。
        append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。但当slice中没有剩余空间(即(cap-len) == 0)时,此时将动态分配新的数组空间。返回的slice数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice则不受影响。
slice内容复制(copy)
   
   n1 := copy(s, a[x:y]) 
    copy:函数copy用于将内容从一个数组或切片复制到另一个切片,被复制的是数组元素的值而不是引用。如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制,并且返回复制的元素的个数。
    
    var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7} //省略长度可以用...号,长度值会自动计算
    var s = make([]int, 6)
<关键字:slice range append copy >
转载请注明出处:http://blog.csdn.net/jesseyoung/article/details/33737813


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:JesseYoung

查看原文:golang数据类型-slice(切片)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

12439 次点击  ∙  1 赞  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传