数组和切片4
切片的遍历:
切片的遍历和数组一样,也有两种方式
1)for 循环常规方式遍历
2)for-range 结构遍历切片
两种方式都在下面的代码里:
案例演示:
func main() {
//使用常规的for循环遍历切片
var arr [5]int = [...]int{10,20,30,40,50}
slice := arr[1:4] // 20, 30, 40
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 \n", i, v)
}
}
切片的注意事项和细节说明:
切片初始化时 var slice = arr[startIndex:endIndex]
说明:从arr 数组下标为startIndex,取到下标为endIndex的元素,不含arr[endIndex]。
切片初始化时,仍然不能越界。范围在 [0-len(arr)] 之间,但是可以动态增长。
1)var slice = arr[0:end] 可以简写 var slice = arr[:end]
2)var slice = arr[start:len(arr)] 可以简写: var slice = arr[start:]
3)var slice = arr[0:len(arr)] 可以简写: var slice = arr[:]
cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用
切片可以继续切片
用append内置函数,可对切片进行动态追加
func main() {
//用append内置函数,可以对切片进行动态追加
var slice3 = []int{100, 200, 300}
//通过append直接给slice3追加具体的元素
slice3 = append(slice3, 400, 500, 600)
//通过append将切片slice3追加给slice3
slice3 = append(slice3, slice3...)
fmt.Println("slice3=", slice3)
}
切片append操作的底层原理分析:
1)切片append操作的本质就是对数组扩容
2)go底层会创建一个新的数组newArr(按照扩容后大小)
3)将slice原来包含的元素拷贝到新的数组newArr
4)slice重新引用到newArr
5)注意newArr是在底层来维护的,程序员不可见
6)案例演示说明:
切片的拷贝操作:
切片使用copy内置函数完成拷贝,举例说明:
func main() {
var slice4 []int = []int {1,2,3,4,5}
var slice5 = make([]int, 10)
copy(slice5, slice4)
fmt.Println("slice4=", slice4)
fmt.Println("slice5=", slice5)
}
对上面代码的说明:
(1)copy(para1, para2):参数的数据类型都是切片类型。
(2)按照上面的代码来看,slice4和slice5的数据空间是独立的,相互不影响,也就是说 slice4[0]=999,slice5[0] 仍然是1。
思考题:下面的代码有没有错误:
var a []int = []int {1,2,3,4,5}
var slice = make([]int, 1)
fmt.Println(slice) //0
copy(slice, a) //这里是不会报长度不够这个错的,虽然长度只有1。长度有多大,就拷贝几个值过来
fmt.Println(slice) //1
说明:上面的代码没有问题,可以运行,最后输出的结果是 【1】
string和slice:
1)string底层是一个byte数组,因此string也可以进行切片处理
案例演示:
func main() {
str := "hello@atguigu"
slice := str[6:]
fmt.Println("slice=",slice)
}
2)string和切片在内存的形态,以“abcd” 画出内存示意图
3)string是不可变的,也就说不能通过 str[0] = 'z' 方式来修改字符串
4)如果需要修改字符串,可以先将string -> []byte / 或者 []rune -> 修改 -> 重写转成string
func main() {
str := "hello@atguigu"
slice := str[6:]
fmt.Println("slice=",slice)
//str[0] = 'z' [编译不会通过,报错,原因是string是不可变的]
// arr1 := []byte(str)
// arr1[0] = 'z'
// str = string(arr1)
// fmt.Println("str=", str)
//细节,我们转成[]byte后,可以处理英文和数字,但是不能处理中文
//原因是 []byte 按字节来处理的,而一个汉字是3个字节,因此就会出现乱码
//解决方法是将 string 转成 []rune 即可,因为 []rune是按字符处理,兼容汉字
arr1 := []rune(str)
arr1[0] = '北'
str = string(arr1)
fmt.Println("str=", str)
}