Golang从入门到精通(十二):Golang复合数据之slice

来源:互联网 发布:游船上有网络么? 编辑:程序博客网 时间:2024/05/16 12:16

数组和slice的区别

Go 语言中数组是具有固定长度而且拥有零个或者多个相同或相同数据类型元素的序列。由于数组长度固定,所以在Go语言比较少直接使用。而slice长度可增可减,使用场合比较多。更深入的区别在于:数组在使用的过程中都是值传递,将一个数组赋值给一个新变量或作为方法参数传递时,是将源数组在内存中完全复制了一份,而不是引用源数组在内存中的地址。为了满足内存空间的复用和数组元素的值的一致性的应用需求,slice出现了,每个slice都是都源数组在内存中的地址的一个引用,源数组可以衍生出多个slice,slice也可以继续衍生其他slice。

数组

Go语言数组中每个元素是按照索引来访问的,索引从0到数组长度减1。Go语言内置函数len可以返回数组中的元素个数。

数组定义初始化

初始化方式有四种:指定/不指定长度*初始化部分/全部元素两两组合。示例代码如下:

var a [3] int   //3个整数型的数组,初始值是3个0arr:=[5]int{1,2,3,4,5}   //长度为5var array2 = [...]int{6, 7, 8} //不声明长度q := [...] int {1,2,3} //不声明长度r := [...] int {99:-1}  //长度为100的数组,只有最后一个是-1,其他都是0

数组作为函数参数

Go语言中数组也可以作为参数:

package main import "fmt"func modify_arr(array [5]int) {    array[0]=10    fmt.Println("In modify_arr,array values is:",array)}func main() {    arr:=[5]int{1,2,3,4,5}    modify_arr(arr)    fmt.Println("In main,array values is:",arr)}

slice

Go 语言中数组是值类型,长度不可伸缩;而slice 是引用类型,长度可动态增长。

slice概念

Go 语言中,slice表示一个拥有相同类型元素的可变长度序列。slice通常被写为[]T,其中元素的类型都是T;它看上去就像没有长度的数组类型。
数组和slice其实是紧密关联的。slice 可以看成是一种轻量级的数据结构,可以用来访问数组的部分或者全部元素,而这个数组称之为 slice 的底层数组。slice 有三个属性:指针,长度和容量。指针指向数组的第一个可以从 slice 中访问的元素,这个元素不一定是数组的第一个元素。长度指的是 slice 中的元素个数,不能超过 slice 的容量。指针通常是从指向数组的第一个可以从 slice 中访问的元素,这个元素不一定是数组的第一个元素。长度指的是 slice 中的元素个数,它不能超过 slice 的容量。容量的大小通常大于等于长度,会随着元素个数增多而动态变化。Go语言的内置函数 len 和 cap 用来返回 slice 的长度和容量。

slice定义初始化

slice 初始化依赖于数组,可见如下代码和注释:

s1 := []int{1, 2, 3}    //注意与数组初始化的区别,在内存中构建一个包括有3个元素的数组,然后将这个数组的应用赋值给s这个slice  a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}  //a是数组 s2 := a[2:8]                 //从数组中切片构建slice   s3 := make([]int, 10, 20)    //make函数初化,len=10,cap=20

其中 a 是数组 , s1,s2,s3 是 slice。

slice中len和cap关系

Go语言的内置函数len 和 cap 用来返回slice的长度和容量。在追加元素时,如果容量cap不足时,cap**一般**变为原来的2倍来实现扩容。

slice的cap扩容规则:
- 如果新的cap大小是当前cap的2倍以上,则直接扩容为这个新的cap;
- 否则循环以下操作:如果当前cap小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新的cap。

slice一般用append函数追加元素,append第一个参数是slice,第二个参数是元素。示例代码如下:

package main import "fmt"func print_info(my_slice[]int) {    fmt.Println("len :",len(my_slice))    fmt.Println("cap :",cap(my_slice))    for i,v :=range my_slice{        fmt.Println("element[",i,"]=",v)    }}func main() {    my_slice01:=[]int{1,2,3,4,5}    my_slice02:=make([]int,5)    my_slice03:=make([]int,5,6)    my_slice04:=append(my_slice03,8,9,10)    print_info(my_slice01)    print_info(my_slice02)    print_info(my_slice03)    print_info(my_slice04)}

slice的合并

append的第一个参数是slice,第二个参数是元素。结合下Go语言函数的不定参数,我们可以用append优雅地实现两个slice的拼接。例如,下面的函数能合并两个slice的全部元素到一个新的slice,并返回新slice的长度len和容量cap:

        func slice_add(slice01[]int,slice02[]int)(int,int){            new_slice := append(slice01,slice02...)            return len(new_slice),cap(new_slice)        }

slice作为函数参数

注意和数组作为函数参数的区别:

package mainimport (    "fmt")func main() {    a := []int{1, 2, 3, 4, 5}    var b = a[0:3]    var c = [...]int{3, 6, 9, 2, 6, 4}    d := c[0:2]    sliceInfo(b)    fmt.Printf("sum of b is %d\n", sum(b))    fmt.Printf("sum of d is %d\n", sum(d))}func sum(a []int) int {    s := 0    for i := 0; i < len(a); i++ {        s += a[i]    }    return s}func sliceInfo(x []int) {    fmt.Printf("len is %d ,cap is %d,  slice is %v\n", len(x), cap(x), x)}

slice的不可比性

Go 语言中slicemap ,func一样,不支持 ==操作符,就是不能直接比较,唯一合法的就是和nil作比较。开发中经常会遇到需要比较两个slice包含的元素是否完全相等的情况,这个时候只能遍历两个slice中的所有元素 ,看它们是否完全相等。

阅读全文
0 0
原创粉丝点击