Golang中的切片
- 基本介绍
- 切片在内存中的形式
- 切片使用的三种方式
- 方式一:
- 方式二:
- 方式三:
- 切片使用的区别
- 切片的遍历
- 切片注意事项和细节说明
- append函数
- 切片的拷贝操作
- string和slice
基本介绍
- 1.切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制
- 2.切片的使用和数组类型,遍历切片、访问切片的元素和求切片长度len(slice)都是一样
- 3.切片的长度是可以变化的,因此切片是一个可以动态变化数组
- 4.切片定义的基本语法:
- var 变量名 [] 类型, 比如: bar a [] int
package main
import (
"fmt"
)
func main() {
var intArr [5]int = [...]int{1, 33, 22, 55, 66}
//slice就是切片名
//intArr[1:3]表示slice引用到intArr这个数组
//引用intArr数组的起始下标为1, 最后的下标为3(但是不包含3)
slice := intArr[1:3]
fmt.Println("intArr=", intArr)
fmt.Println("slice 的元素是:", slice)
fmt.Println("slice 的元素个数是:", len(slice))
fmt.Println("slice 的容量", cap(slice)) //切片的容量是可以动态变化的
}
/*
intArr= [1 33 22 55 66]
slice 的元素是: [33 22]
slice 的元素个数是: 2
slice 的容量 4
*/
切片在内存中的形式
- 切片底层的数据结构可以理解成是一个结构体struct
- 切片确实是一个引用类型
切片使用的三种方式
方式一:
定义一个切片,然后让切片去引用一个已经创建好的数组,前面的案例就是这样的
方式二:
通过make来创建切片
基本语法:var 切片名 []type = make([], len, [cap])
package main
import (
"fmt"
)
func main() {
var slice []int = make([]int, 4, 10)
fmt.Println(slice) //默认值为0
fmt.Println("slice len=", len(slice), "slice cap=", cap(slice))
slice[0] = 100
slice[2] = 200
fmt.Println(slice)
}
/*
[0 0 0 0]
slice len= 4 slice cap= 10
[100 0 200 0]
*/
总结:
- 1.通过make方式创建切片可以指定切片的大小和容量
- 2.如果没有给切片的各个元素赋值,那么就会使用默认值
- 3.通过make方式创建的切片对应的数组的有make底层维护,对外不可见,只能通过slice去访问各个元素
方式三:
定义一个切片,直接就指定具体数组,使用原理类似make的方式
func main(){
var slice []int = []int {1, 3, 5}
fmt.Println(slice)
}
切片使用的区别
- 方式一是直接引用数组,这个数组是事先存在的,程序员可见的
- 方式二是通过make来创建切片,make也会创建一个数组,是有切片在底层进行维护,程序员是看不见的
切片的遍历
package main
import (
"fmt"
)
func main() {
//使用常规的for循环遍历切片
var arr [5]int = [...]int{4, 5, 6, 7, 8}
slice := arr[1:4]
for i :=0; i < len(slice); i++ {
fmt.Printf("slice[%v]=%v ", i, slice[i])
}
fmt.Println()
//使用for-range方式切片
for i, v := range slice {
fmt.Printf("i=%v v=%v ", i, v)
}
}
//slice[0]=5 slice[1]=6 slice[2]=7
//i=0 v=5 i=1 v=6 i=2 v=7
切片注意事项和细节说明
- 切片初始化时 var slice = arr[startindex:endindex]
- 说明:从arr数组下标为startindex,取到endindex的元素(不含arr[endindex])
- 切片初始化时,任然不可以越界。范围在[0-len(arr)之间],但是可以动态增长
- var slice = arr [0:end]可以简写:var slice = arr [:end]
- var slice = arr[start:len(arr)]可以简写:var slice = arr[start:]
- var slice = arr[0:len(arr)]可以简写:var slice = arr[:]
- cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素
- 切片定义完后,还不能使用,因为本省是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用
- 切片可以继续切片
append函数
用append内置函数,可以对切片进行动态追加
package main
import (
"fmt"
)
func main() {
var slice []int = []int{100, 200, 300}
//通过append直接给slice追加具体的元素
slice = append(slice, 400, 5000)
fmt.Println("slice", slice)
//通过append将切片slice追加给slice
slice = append(slice, slice...)
fmt.Println("slice", slice)
}
/*
slice [100 200 300 400 5000]
slice [100 200 300 400 5000 100 200 300 400 5000]
*/
底层原理分析
1.切片append操作的本质就是对数组扩容
2.go底层会创建一下新的数组newArr(安装扩容后大小)
3.将slice原来包含的元素拷贝到新的数组newArr
4.slice重新引用到newArr
5.注意newArr是在底层来维护的,程序员不可见
切片的拷贝操作
copy(para1,para2)参数的数据类型是切片
由下面的案例可知,slice1和slice2的数据空间是独立,相互不影响,也就是说slice[0]=999,slice2[0]任是1
package main
import (
"fmt"
)
func main() {
var slice1 []int = []int{1, 2, 3, 4, 5}
var slice2 = make([]int, 10)
copy(slice2, slice1)
fmt.Println("slice1", slice1)
fmt.Println("slice2", slice2)
}
/*
slice1 [1 2 3 4 5]
slice2 [1 2 3 4 5 0 0 0 0 0]
*/
string和slice
- slice底层是一个byte数组,因此string也可以进行切片处理
- sting是不可变的,也就是说不能通过str[0]='z’方式来修改字符串
- 如果需要修改字符串,可以先将string->[]byte/或者[]rune->修改->重写转成string
package main
import (
"fmt"
)
func main() {
str := "hello@wings"
//使用切片获取内容
slice := str[6:]
fmt.Println("slice=", slice)
//[]byte可以处理英文和数字但是不能处理中文
//[]rune是按照字符处理,兼容汉字
arr1 := []byte(str)
arr1[0] = 'z'
str = string(arr1)
fmt.Println("str=", str)
}
//slice= wings
//str=zhello@wings