slice切片的四种声明定义方式,切片的截取、修改与追加

134 阅读3分钟

 一、切片定义

定义切片

var identifier []type

切片不需要说明长度。 或使用make()函数来创建切片:

var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)

make([]T, length, capacity)

空切片:一个切片在未初始化之前默认为 nil,长度为 0 

package main

import "fmt"

func main() {
   var numbers []int

   printSlice(numbers)

   if(numbers == nil){
      fmt.Printf("切片是空的")
   }
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

 完整代码:

package main

import "fmt"

func main() {
	//第一种::声明slice1是一个切片,并且初始化,默认值是1,2,3,长度是3
	//slice1 := []int{1, 2, 3}

	//第二种::声明一个slice1是一个切片,但是并没有给slice分配空间
	//var slice1 []int
	//这个时候如果写slice1【0】=1,就会报错,因为还没有给slice1分配空间
	//slice1[0] = 1,错误是:"runtime error: index out of range [0] with length 0"
	//通过make开辟空间
	//slice1 = make([]int, 3) //开辟三个容量,此时默认值是0
	//slice1[1] = 1000

	//第三种::声明一个slice1是一个切片,同时给slice分配3个空间,初始化为0
	//var slice1[]int=make([]int, 3)
	//或者用通过:=推导出slice是一个切片
	slice1 := make([]int, 3)
	//fmt.Printf("len = %d,slice = %v\n", len(slice1), slice1) //"%v表示打印所有信息"

	//判断一个slice是否为0
	if slice1 == nil {
		fmt.Println("slice是一个空切片")//第十行会是一个空切片
	} else {
		fmt.Println("slice不是一个空切片")//20行的可不是空切片
	}

}

make(1,2,3):1.表示类型,2.表示长度,3.表示容量

二、切片追加

使用append进行追加,代码如下

package main

import "fmt"

func main() {
	var numbers = make([]int, 3, 5) //len=3,cap=5
	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)

	//想numbers追加一个元素1,len=4,cap=5
	numbers = append(numbers, 1)
	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)

	numbers = append(numbers, 2)
	//向一个满容cap的slice追加元素
	numbers = append(numbers, 3)
	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)
	//cap会扩大两倍
}

注意:当cap(容量)满了的时候再去追加,cap会自动变成原来的两倍。 总结,如下图

 三、切片截取

s := arr[startIndex:endIndex] 

将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片(前闭后开),长度为endIndex-startIndex

s := arr[startIndex:] 

缺省endIndex时将表示一直到arr的最后一个元素

s := arr[:endIndex] 

缺省startIndex时将表示从arr的第一个元素开始

截取很简单的,直接看代码吧

package main

import "fmt"

func main() {
	s := []int{1, 2, 3} //len=3,cap=3
	s1 := s[0:2]        //从索引下标0开始,左闭右开,也就是说截取index=0和1两个元素。即截取1,2
	fmt.Println(s1)     //【1 2】
	//注意此时改变了s1的第一个值,s的值也会改变,因为他俩指定的同一块内存地址
	s1[0] = 100
	fmt.Println(s)
	fmt.Println(s1)
	//如果想不改变s的值,那么可以用copy进行拷贝
	s2 := make([]int, 3)
	copy(s2, s) //将s中的值拷贝给s2
	s2[0] = 100
	//fmt.Println(s)  //[1 2 3]
	fmt.Println(s2) //[100 2 3]
}

当然我还演示了,如何在截取之后改变截取的值而不改变原切片的值

四、切片修改

slice没有自己的任何数据。它只是底层数组的一个表示。对slice所做的任何修改都将反映在底层数组中。

示例代码:

package main

import (  
    "fmt"
)

func main() {  
    darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
    dslice := darr[2:5]
    fmt.Println("array before",darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println("array after",darr) 
}

运行结果:

array before [57 89 90 82 100 78 67 69 59]  
array after [57 89 91 83 101 78 67 69 59]  

当多个片共享相同的底层数组时,每个元素所做的更改将在数组中反映出来。

示例代码:

package main

import (  
    "fmt"
)

func main() {  
    numa := [3]int{78, 79 ,80}
    nums1 := numa[:] //creates a slice which contains all elements of the array
    nums2 := numa[:]
    fmt.Println("array before change 1",numa)
    nums1[0] = 100
    fmt.Println("array after modification to slice nums1", numa)
    nums2[1] = 101
    fmt.Println("array after modification to slice nums2", numa)
}

运行结果:

array before change 1 [78 79 80]  
array after modification to slice nums1 [100 79 80]  
array after modification to slice nums2 [100 101 80] 

总结:

切片Slice:
1.每一个切片引用了一个底层数组
2.切片本身不存储任何数据,都是这个底层数组存储,所以修改切片也就是修改这个数组中的数据
3.当向切片中添加数据时,如果没有超过容量,直接添加,如果超过容量,自动扩容(成倍增长)
4.切片一旦扩容,就是重新指向一个新的底层数组