Go语言切片(Slice)的深入理解

了解Go语言的切片(Slice)之前,我们先了解下Go语言的数组。

数组是一个线性数据结构,具有相同唯一类型的一组已编号且长度固定的数据项序列,数组的存储类型可以是任意类型。

1、声明一个int类型的数组: 

var myArr [10]int;

2、初始化数组:

myArr=[10]int{1,2,3,4,5};

使用fmt.Println(myArr)输出结果为:[1 2 3 4 5 0 0 0 0 0]

3、数组的长度

使用fmt.Println(len(myArr))输出结果为:10

以上数组的操作和其他语言如Java、.net类似,也体现了数组的基本特征。

下面我们使用数组进行参数的传递。

func modifyArray(arr [10]int){ 

    for index:=0;index<len(arr);index++{

        arr[index]+=1;

    }

}

fmt.Println(myArr);

输出结果为:[1 2 3 4 5 0 0 0 0 0]

数组的值没有发生变化,这一点说明Go语言的数字是按照值类型传递参数的。

注意上述的改变数组的方法参数是带有数字的,为什么要这样我们等会再阐述。

现在我们使用指针作为形参来进行数组的传值,方法改为:

func modifyArray(arr *[10]int){

    for index:=0;index<len(arr);index++{

        arr[index]+=1;

    }

}

执行该函数并输出数组:

modifyArray(&myArr);//注意这里传递的是数组的地址

fmt.Println(myArr);

输出结果为:[2 3 4 5 6 1 1 1 1 1]

数组的值修改成功。

以上实例说明,数字的声明和初始化是需要指定个数的,包括数组作为参数进行传递的时候也是需要指定个数,否则会报错。

再强调一遍:数字的声明和初始化是需要指定个数。

如果我们不想指定个数呢,每次都指定个数很麻烦的好不好,那我们就指定个数试一试,程序员就要任性。

重新定义变量myArr:

Var myArr=[]int{1,2,3,4,5,0,0,0,0,0};

fmt.Println(myArr);

输出结果为:[1 2 3 4 5 0 0 0 0 0]

答案是可以的。

下面重新进行参数的传递。

func modifyArray(arr []int){    //注意[]int没有指定个数

    for index:=0;index<len(arr);index++{

        arr[index]+=1;

    }

}

fmt.Println(myArr);

输出结果为:[2 3 4 5 6 1 1 1 1 1]

MyArr的值已经被修改了,这是什么情况?

我们回想一下刚才对数组强调的一句话:数字的声明和初始化是需要指定个数。如果不指定个数,那就不是数组,而是切片(Slice)。

使用var myArr=[]int{1,2,3,4,5,0,0,0,0,0};实际上是定一个一个切片。切片在参数传递的使用是传递的引用。

那么,到底什么是切片呢?切片是一个数据类型还是一个方法?

切片我们可以理解为“动态数组”,切片内部封装了一个数组指针,并能够通过切片实现数组的“动态”效果。

Slice的数据机构如下:

type slice struct {

    array unsafe.Pointer //指向数组的指针

    len   int             //切片长度

    cap   int            //切片容量

}

Slice不是一个数组,而是一个特殊的结构体,当我们创建一个切片的使用,相当于创建了一个数组,该数组的指针就保存在切片内,任何对指针的操作都会反映到数组上,所以抛开这点,切片和数组的操作是一样的。

除了刚才的方式定义切片,我们也可以使用如下方式定义:

var sliceArr []int = make([]int, 10)

fmt.Println(slice1);

输出结果为:[0 0 0 0 0 0 0 0 0 0]

我们也可以通过截取数组的方式创建切片:

var myArr [10]int;

myArr=[10]int{1,2,3,4,5,0,0,0,0,0};

s := myArr[0:5];//从0开始,长度为5的元素到切片,这时候切片的数值指针指向Arr[0:5]

fmt.Println(s);

输出结果为:[1,2,3,4,5]

modifyArray(s);//切片元素值++

fmt.Println(s);

fmt.Println(myArr);

输出结果为:[2 3 4 5 6]

[2 3 4 5 6 0 0 0 0 0]

这时候除了切片的元素值变化,数组Arr的值也发生了变化。

Go语言切片的append   

s:=[]int{1,2,3,4,5}

    fmt.Println(s);

    fmt.Println(&s[0]);

    s=append(s,6);

    fmt.Println(s);

    fmt.Println(&s[0]);

输出结果:

[1 2 3 4 5]

0xc042072090

[1 2 3 4 5 6]

0xc042086000

数组首个元素的指针地址发生了变化,说明append在扩充时,只要超过了原有数组的上限,就会自动创建一份拷贝。

理解了以上,我们差不多也就对Go的数组和切片有个大致的了解,只要多加练习,就能够熟练掌握这些知识点。

 

猜你喜欢

转载自blog.csdn.net/luoye4321/article/details/82019950