切片是一个引用类型,内部结构包括地址、长度、和容量,实际上切片是数组的一个引用,声明切片可以有几种方式
直接声明,该声明方式,切片的内容是一个nil,长度和容量都是0。
var slice []int
fmt.Printf("sliceMake长度%v,容量%v,初始值%v\n", len(slice), cap(slice), slice)
if slice == nil {
fmt.Println("slice is nil")
}
make关键字声明,该声明方式,切片的内容不是一个nil,长度和容量都是0。
//make声明和创建
sliceMake := make([]int, 0)
if sliceMake == nil {
fmt.Println("sliceMake is nil")
}
fmt.Printf("sliceMake长度%v,容量%v,初始值%v\n", len(sliceMake), cap(sliceMake), sliceMake)
sliceMake1 := make([]int, 5, 10)
fmt.Printf("sliceMake1长度%v,容量%v,初始值%v\n", len(sliceMake1), cap(sliceMake1), sliceMake1)
直接声明和初始化,该方式的过程是先创建了一个数组,然后在创建切片指向该数组
//直接声明和初始化
var areaSlice = []string{"广州", "北京", "上海", "深圳", "武汉", "重庆", "成都", "洛阳"}
fmt.Printf("areaSlice长度%v,容量%v,初始值%v\n", len(areaSlice), cap(areaSlice), areaSlice)
根据数组切分初始化切片,该方式有个特别注意的地方,就是切片的容量怎么定义,按该方式去初始化,出来切片的容量是从他第一个元素开始数,到其底层元素数组元素末尾的个数,拿下面这个areaArr[:3]来说,该切片的长度是从底层数组第0个元素开始计算,直到第3个元素切割(不包括3),所以他的长度是3,而容量则是是从底层数组第0个元素开始计算,直到areaArr数组的最后一个元素,也就是areaSlice的容量其实是8,
//数组切分创建和初始化切片
var areaArr = [...]string{"广州", "北京", "上海", "深圳", "武汉", "重庆", "成都", "洛阳"}
//忽略掉slice的起始索引,表示从数组的起始位置进行切分
areaSlice1 := areaArr[:3]
fmt.Printf("areaSlice1长度%v,容量%v,初始值%v\n", len(areaSlice1), cap(areaSlice1), areaSlice1)
//忽略掉slice的结束索引,表示从使用数组的长度作为结束索引
areaSlice2 := areaArr[4:]
fmt.Printf("areaSlice2长度%v,容量%v,初始值%v\n", len(areaSlice2), cap(areaSlice2), areaSlice2)
//同时忽略开始和结束索引,就是包含数组所有元素的一个slice
areaSlice3 := areaArr[:]
fmt.Printf("areaSlice3长度%v,容量%v,初始值%v\n", len(areaSlice3), cap(areaSlice3), areaSlice3)
切片的遍历
//range方式
var areaSlice = []string{"广州", "北京", "上海", "深圳", "武汉", "重庆", "成都", "洛阳"}
for index, item := range areaSlice {
fmt.Printf("areaSlice遍历第%v个元素的值为%v\n", index, item)
}
//for方式
for i := 0; i < len(areaSlice); i++ {
fmt.Printf("areaSlice遍历第%v个元素的值为%v\n", i, areaSlice[i])
}
追加切片元素(append)
sliceMake := make([]int, 1)
//追加多个元素
sliceMakeAppend := append(sliceMake, 1, 2)
//追加一个元素
sliceMakeAppend1 := append(sliceMakeAppend, 1)
slice1 := []string{"广州", "北京"}
slice2 := []string{"广州", "北京"}
//追加切片
sliceMerge := append(slice1, slice2...)
实际上,append可以在切片声明之后直接追加,而不需要make,因为append底层实现有make方法,在不符合长度的时候,会初始化该切片。
var slice []int
if slice == nil {
fmt.Printf("slice is nil\n")
}
slice = append(slice, 11)
if slice != nil {
fmt.Printf("slice is not nil\n")
}
fmt.Printf("slice长度%v,容量%v,初始值%v\n", len(slice), cap(slice), slice)
//输出
slice is nil
slice is not nil
slice长度1,容量2,初始值[11]
复制一个切片(copy)
//切片复制
sliceCopy := []string{"广州", "北京"}
sliceNew := make([]string, 2)
copy(sliceNew, sliceCopy)
切片操作字符串,利用切片可以切割字符串,但是要注意的是,切片切割字符串,索引是按照字节数来计算的,如果碰到有中文或者特殊字符的,切割出来并不是我们预想的结果。
var strByte = "this is test"
testSlice := strByte[:4]
fmt.Printf("testSlice长度%v,初始值%v,首个元素的内存地址%p\n", len(testSlice), testSlice)
//切片字符串,索引代表的是字节数而非rune的数,例如下面的"go语言,"长度为9个字节,一个汉字占用3个字节
var strRune = "go语言,Hello!"
testSlice1 := strRune[:7]
fmt.Printf("testSlice1长度%v,初始值%v,首个元素的内存地址%p\n", len(testSlice1), testSlice1)
碰到字符串是中文或者特殊字符的,可以考虑转为rune类型的切片,再去提取对应的字符串。
var strByte = "this is test"
var strRune = "go语言,Hello!"
var tempByte = []byte(strByte)
fmt.Printf("tempByte长度%v,容量%v,初始值%v,首个元素的内存地址%p\n", len(tempByte), cap(tempByte), tempByte, &tempByte[0])
var newByteSlice = make([]byte, 0)
for i := 0; i < 4; i++ {
newByteSlice = append(newByteSlice, tempByte[i])
}
newStr := string(newByteSlice)
fmt.Printf("newStr值%v,类型%T\n", newStr, newStr)
var tempRune = []rune(strRune)
fmt.Printf("tempRune长度%v,容量%v,初始值%v,首个元素的内存地址%p\n", len(tempRune), cap(tempRune), tempRune, &tempRune[0])
var newRuneSlice = make([]rune, 0)
for i := 0; i < 7; i++ {
newRuneSlice = append(newRuneSlice, tempRune[i])
}
newRuneStr := string(newRuneSlice)
fmt.Printf("newStr值%v,类型%T\n", newRuneStr, newRuneStr)
发表评论