【第三十三篇】GO 切片注意事项和细节说明

136 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情

一、切片注意事项和细节说明

  • 切片初始化时,var slice = arr [startIndex:endlndex]
    • 说明:从 arr 数组下标为startIndex ,取到下标为 endlndex 的元素(不含 arr [endlndex]
  • 切片初始化时,仍然不能越界。范围在 [0 - len(arr)]之间,但是可以动态增长,
package main

import "fmt"

func main() {
	// 使用常规的 for 循环遍历切片
	var arr [5]int = [...]int{10, 20, 30, 40, 50}
	slice := arr[1:4]

	// 使用for - range 方式来遍历切片
	for i, v := range slice {
		fmt.Printf("i = %v	v = %v\n", i, v)
	}

	// 注意点:
	fmt.Println(slice[3])
}

  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一个空间供切片来使用。
  • 切片可以继续切片
package main

import "fmt"

func main() {
	// 使用常规的 for 循环遍历切片
	var arr [5]int = [...]int{10, 20, 30, 40, 50}
	slice := arr[1:4]

	// 使用for - range 方式来遍历切片
	for i, v := range slice {
		fmt.Printf("i = %v	v = %v\n", i, v)
	}

	// 注意点:
	// slice [20, 30, 40,]	[30]
	slice2 := slice[1:2]
	slice2[0] = 100 //因为 arr ,slice 和 slice2 指向的数据空间是同一个,因此 slice2[0] = 100
	fmt.Println("slice2 = ", slice2)
	fmt.Println("slice = ", slice)
	fmt.Println("arr = ", arr)
}

  • append 内置函数,可以对切片进行动态追加。
package main

import "fmt"

func main() {

	// 用 append 内置函数,可以对切片进行动态追加
	var slice3 []int = []int{100, 200, 300}
	fmt.Println("(原)slice3 = ", slice3)

	// 进行追加,通过append直接给slice3追加具体的元素
	slice4 := append(slice3, 400, 500, 600)
	fmt.Println("(追加元素)slice4 = ", slice4)

	// 通过 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 是在底层来维护的,程序员不可见。

切片的拷贝操作:

  • 切片使用copy内置函完成拷贝,举例说明:
package main

import "fmt"

func main() {

	var a []int = []int{1, 2, 3, 4, 5}

	var slice = make([]int, 10)
	fmt.Println(slice)

	copy(slice, a)
	fmt.Println(slice)

}

对上面代码的说明:

  1. copy(para1 ,para2):para1para2 都是切片类型。
  2. 必须都是切片类型,才能执行拷贝操作。
  3. 按照上面的代码来看,a 和 slice 的空间都是相互独立的,互不影响。

切片是引用类型,所以在传递时,遵守引用传递机制。请看如下代码:

package main

import "fmt"

func main() {
	var slice []int
	var arr [5]int = [...]int{1, 2, 3, 4, 5}
	slice = arr[:]
	var slice2 = slice
	slice2[0] = 10
	fmt.Println("slice2", slice2)
	fmt.Println("slice", slice)
	fmt.Println("arr", arr)
}

package main

import "fmt"

func test(slice []int) {
	slice[0] = 100 // 这里修改slice[0],会改变实参
}

func main() {
	var slice = []int{1, 2, 3, 4}
	fmt.Println("slice = ", slice)
	test(slice)
	fmt.Println("slice = ", slice)
}