【7.0】Go语言基础之数组、切片

发布时间 2023-11-11 21:07:43作者: Chimengmeng

【一】数组

  • 数组是一种类型,可以连续存储数据,但是数据类型的是一致的。
    • 类似于 Python 中的列表,是一种数据结构

【1】数组的定义

package main

import "fmt"

func main() {
	// 定义数组
	// 定义一个长度为 3 的数组,里面的数据类型为 int 类型
	// 定义好数组以后,大小就固定了,后期不能修改大小
	var a [3]int = [3]int{4, 5, 6}
	fmt.Println(a) // [4 5 6]
}

【2】数组的使用

package main

import "fmt"

func main() {
	// 定义数组
	// 定义一个长度为 3 的数组,里面的数据类型为 int 类型
	// 定义好数组以后,大小就固定了,后期不能修改大小
	var a [3]int = [3]int{4, 5, 6}
	fmt.Println(a) // [4 5 6]

	// 数组的使用 : 修改值 , 取值 --- 根据下标(索引)取值
	a[0] = 99
	fmt.Println(a) // [99 5 6]
	fmt.Println(a[0])
}

【3】数组大小固定

package main

import "fmt"

func main() {
	// 定义数组
	// 定义一个长度为 3 的数组,里面的数据类型为 int 类型
	// 定义好数组以后,大小就固定了,后期不能修改大小
	var a = [3]int{3} // 数组大小固定,赋初值,可以少(如果不足,不足的位置是每个数据类型的0值)但是不能多
	fmt.Println(a)    // [3 0 0]

	// var b = [3]int{3, 4, 5, 6} // Index out of bounds: 3
	// fmt.Println(b)             // [3 0 0]
}

【4】指定位置赋初值

package main

import "fmt"

func main() {
	// 定义数组
	// 定义一个长度为 3 的数组,里面的数据类型为 int 类型
	// 定义好数组以后,大小就固定了,后期不能修改大小
	// 数组大小固定,赋初值,可以少(如果不足,不足的位置是每个数据类型的0值)但是不能多
	// 指定位置赋初值 --- 指定从 0 开始 ,第 25 个位置是 3 ,其他都是默认值
	var a = [30]int{25: 3}
	fmt.Println(a) // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0]
}

【5】定义数组并固定长度

package main

import "fmt"

func main() {
	// 定义数组
	// 定义好数组以后,大小就固定了,后期不能修改大小
	// 数组大小固定,赋初值,可以少(如果不足,不足的位置是每个数据类型的0值)但是不能多
	// 定义数组必须赋初值,并且赋初值必须指定长度
	// 虽然使用 ... 初始化,但是长度也固定了,根据值的多少确定长度
	var a = [...]int{3, 4, 5}
	fmt.Println(a)          // [3 4 5]
	fmt.Printf("类型为 %T", a) // 类型为 [3]int  --- 长度为3的int类型
}

【6】数组的循环

package main

import "fmt"

func main() {
	// 数组的循环
	var a = [...]int{6, 7, 8}

	// 计算数组的长度
	fmt.Println(len(a)) // 3

	// 数组的循环  -- 正向循环取值
	for i := 0; i < len(a); i++ {
		fmt.Println(a[i]) // 6 7 8
	}

	// 数组的循环 -- 反向取值
	for i := len(a) - 1; i >= 0; i-- {
		fmt.Println(a[i]) // 8 7 6
	}

	// 数组的循环 -- 基于迭代的循环 , range 是一个关键字
	for index, value := range a {
		fmt.Println("当前索引 :>>>> ", index, "当前值 :>>>> ", value)
		// 当前索引 :>>>>  0 当前值 :>>>>  6
		// 当前索引 :>>>>  1 当前值 :>>>>  7
		// 当前索引 :>>>>  2 当前值 :>>>>  8
	}

	// 数组的循环 -- 基于迭代的循环 , range 是一个关键字 , 可以使用 _ 代替相应的值
	for _, value := range a {
		fmt.Println("当前值 :>>>> ", value)
		// 当前值 :>>>>  6
		// 当前值 :>>>>  7
		// 当前值 :>>>>  8
	}
}

【7】多维数组

package main

import "fmt"

func main() {
	// 多维数组
	// 长度为 3 的数组内又放了一个长度为 4 的 int 数组
	// 外边的数组为 [3] 三个长度 , 内部数组为 [4]int 四个长度且数据类型为 int
	// 所以有 [3][4]int{{}, {}, {}} 外数组 长度 为 3 内数组 长度 为 4
	var a [3][4]int = [3][4]int{{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}}
	fmt.Println(a) // [[1 1 1 1] [2 2 2 2] [3 3 3 3]]

	// 多维数组的循环 : 两层循环
	for _, value := range a {
		fmt.Println("外层数组 :>>>> ", value)
		for _, val := range value {
			fmt.Println("内层数组 :>>>> ", val)
		}
	}
	//外层数组 :>>>>  [1 1 1 1]
	//内层数组 :>>>>  1
	//内层数组 :>>>>  1
	//内层数组 :>>>>  1
	//内层数组 :>>>>  1
	//外层数组 :>>>>  [2 2 2 2]
	//内层数组 :>>>>  2
	//内层数组 :>>>>  2
	//内层数组 :>>>>  2
	//内层数组 :>>>>  2
	//外层数组 :>>>>  [3 3 3 3]
	//内层数组 :>>>>  3
	//内层数组 :>>>>  3
	//内层数组 :>>>>  3
	//内层数组 :>>>>  3
}

【二】切片

  • 切片是由数组建立的一种方便、灵活且功能强大的包装,切片本身不拥有任何数据。
  • 它们只是对现有数组的引用(指针指向数组)

【1】通过数组创建切片

package main

import "fmt"

func main() {
	// 基于数组定义切片

	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	fmt.Println(a)                   // [1 2 3 4 5 6 7 8 9 10]
	fmt.Printf("a 的类型为 :>>>> %T", a) // fmt.Printf("b 的类型为 :>>>> %T", b)

	// 定义切片 --- [] 内不带任何元素,就是切片类型
	var b []int // 把数组从头到尾的引用给 b
	b = a[:]

	fmt.Println(b)                      // [1 2 3 4 5 6 7 8 9 10]
	fmt.Printf("b 的类型为 :>>>> %T \n", b) // b 的类型为 :>>>> []int
}

【2】切片的使用

package main

import "fmt"

func main() {
	// 基于数组定义切片

	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	fmt.Println(a)                   // [1 2 3 4 5 6 7 8 9 10]
	fmt.Printf("a 的类型为 :>>>> %T", a) // fmt.Printf("b 的类型为 :>>>> %T", b)

	// 定义切片 --- [] 内不带任何元素,就是切片类型
	var b []int // 把数组从头到尾的引用给 b
	b = a[:]

	fmt.Println(b)                      // [1 2 3 4 5 6 7 8 9 10]
	fmt.Printf("b 的类型为 :>>>> %T \n", b) // b 的类型为 :>>>> []int

	// 切片的使用 : 取值修改值,同数组
	// 修改值
	b[1] = 999
	fmt.Println("修改后的 b :>>>> ", b) // 修改后的 b :>>>>  [1 999 3 4 5 6 7 8 9 10]
	// 取值
	fmt.Println(b[0]) // 1
}

【3】切片的变化会影响底层数组

package main

import "fmt"

func main() {
	// 基于数组定义切片

	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 定义切片 --- [] 内不带任何元素,就是切片类型
	var b []int // 把数组从头到尾的引用给 b
	b = a[:]

	// 切片的变化会影响底层数组 --- 修改切片
	b[0] = 999
	fmt.Println("这是 a :>>>> ", a) // 这是 a :>>>>  [999 2 3 4 5 6 7 8 9 10]
	fmt.Println("这是 b :>>>> ", b) // 这是 b :>>>>  [999 2 3 4 5 6 7 8 9 10]
}

【4】底层数组的变化也会影响切片

package main

import "fmt"

func main() {
	// 基于数组定义切片

	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 定义切片 --- [] 内不带任何元素,就是切片类型
	var b []int // 把数组从头到尾的引用给 b
	b = a[:]
	
	// 底层数组的变化也会影响切片 --- 修改底层数组
	a[0] = 999
	fmt.Println("这是 a :>>>> ", a) // 这是 a :>>>>  [999 2 3 4 5 6 7 8 9 10]
	fmt.Println("这是 b :>>>> ", b) // 这是 b :>>>>  [999 2 3 4 5 6 7 8 9 10]
}

【5】切片的长度和容量一

package main

import "fmt"

func main() {
	// 基于数组定义切片

	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 切片的长度和容量
	// 数组有长度,并且长度不能变
	// 切片也有长度,但是切片的长度可以变

	var b []int                   // 把数组指定索引的引用给 b
	b = a[0:3]                    // 前闭后开,顾头不顾尾
	fmt.Println("这是 a :>>>> ", a) // 这是 a :>>>>  [1 2 3 4 5 6 7 8 9 10]
	fmt.Println("这是 b :>>>> ", b) // 这是 b :>>>>  [1 2 3]

	// 切片的长度
	fmt.Println("切片 b 的长度 :>>>> ", len(b)) // 切片 b 的长度 :>>>>  3

	// 切片的容量 : 切片的最大长度
	// cap : 内置函数
	fmt.Println("切片 b 的容量 :>>>> ", cap(b)) // 切片 b 的容量 :>>>>  10
}

【6】切片的长度和容量二

package main

import "fmt"

func main() {
	// 基于数组定义切片

	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 切片的长度和容量
	// 数组有长度,并且长度不能变
	// 切片也有长度,但是切片的长度可以变

	var b []int                   // 把数组指定索引的引用给 b
	b = a[2:9]                    // 前闭后开,顾头不顾尾
	fmt.Println("这是 a :>>>> ", a) // 这是 a :>>>>  [1 2 3 4 5 6 7 8 9 10]
	fmt.Println("这是 b :>>>> ", b) // 这是 b :>>>>  [3 4 5 6 7 8 9 ]

	// 切片的长度
	fmt.Println("切片 b 的长度 :>>>> ", len(b)) // 切片 b 的长度 :>>>>  7

	// 切片的容量 : 容量是底层数组决定的,但是不一定是底层数组的大小,得看切片从哪个位置开始引用数组
	// 从切片引用数组的开始位置到结束,是容量的大小
	// cap : 内置函数
	fmt.Println("切片 b 的容量 :>>>> ", cap(b)) // 切片 b 的容量 :>>>>  8
}

【7】通过make创建切片

package main

import "fmt"

func main() {
	// 通过make创建切片
	// make : 内置函数
	// 第一个参数为类型
	// 第二个参数为切片的长度
	// 第三个参数为切片的容量
	var s []int = make([]int, 5, 10)   // 创建了切片,并且赋值了,但是没有放进去值,所以会有默认值
	fmt.Println("这是创建的切片 s :>>>> ", s) // 这是创建的切片 s :>>>>  [0 0 0 0 0]

	// 定义切片并初始化
	var b []int = []int{2, 3, 4, 5}
	fmt.Println("这是创建的切片 b :>>>> ", b)          // 这是创建的切片 b :>>>>  [2 3 4 5]
	fmt.Println("这是创建的切片 b 的长度 :>>>> ", len(b)) // 这是创建的切片 b 的长度 :>>>>  4
	fmt.Println("这是创建的切片 b 的容量 :>>>> ", cap(b)) // 这是创建的切片 b 的容量 :>>>>  4
}

【8】追加切片

package main

import "fmt"

func main() {
	// 通过make创建切片
	// make : 内置函数
	// 第一个参数为类型
	// 第二个参数为切片的长度
	// 第三个参数为切片的容量
	var s []int = make([]int, 5, 6)             // 创建了切片,并且赋值了,但是没有放进去值,所以会有默认值
	fmt.Println("这是创建的切片 s :>>>> ", s)          // 这是创建的切片 s :>>>>  [0 0 0 0 0]
	fmt.Println("这是创建的切片 b 的长度 :>>>> ", len(s)) // 这是创建的切片 b 的长度 :>>>>  5
	fmt.Println("这是创建的切片 b 的容量 :>>>> ", cap(s)) // 这是创建的切片 b 的容量 :>>>>  6

	// 追加切片
	// 返回值 = append(哪个切片,追加的元素)
	s = append(s, 999)
	fmt.Println("这是追加后的切片 s :>>>> ", s)          // 这是追加后的切片 s :>>>>  [0 0 0 0 0 999]
	fmt.Println("这是追加后的切片 b 的长度 :>>>> ", len(s)) // 这是追加后的切片 b 的长度 :>>>>  6
	fmt.Println("这是追加后的切片 b 的容量 :>>>> ", cap(s)) // 这是追加后的切片 b 的容量 :>>>>  6

	// 已经到了 切片的容量的临界值的基础上,再追加新的值
	// 长度会在原来的基础上 +1
	// 容量会在原来的基础上 翻倍(基于原来的容量翻倍)
	s = append(s, 666)
	fmt.Println("这是追加后的切片 s :>>>> ", s)          // 这是追加后的切片 s :>>>>  [0 0 0 0 0 999 666]
	fmt.Println("这是追加后的切片 b 的长度 :>>>> ", len(s)) // 这是追加后的切片 b 的长度 :>>>>  7
	fmt.Println("这是追加后的切片 b 的容量 :>>>> ", cap(s)) // 这是追加后的切片 b 的容量 :>>>>  12
}

【9】追加切片后底层数组的变化

package main

import "fmt"

func main() {
	// 追加切片后底层数组的变化
	// 定义一个长度为 10 类型为int的数组
	a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	s := a[2:9]
	fmt.Println("这是原来的的数组 a :>>>> ", a) // 这是原来的的数组 a :>>>>  [1 2 3 4 5 6 7 8 9 10]
	fmt.Println("这是创建的切片 s :>>>> ", s)  // 这是原来的的数组 a :>>>>  [1 2 3 4 5 6 7 8 9 10]

	// 切片变,底层数组会变
	s[0] = 999
	fmt.Println("这是原来的的数组 a :>>>> ", a) // 这是原来的的数组 a :>>>>  [1 2 999 4 5 6 7 8 9 10]
	fmt.Println("这是修改后的切片 s :>>>> ", s) // 这是修改后的切片 s :>>>>  [999 4 5 6 7 8 9]

	// 数组变,切片也会变
	a[8] = 888
	fmt.Println("这是原来的的数组 a :>>>> ", a) // 这是原来的的数组 a :>>>>  [1 2 999 4 5 6 7 8 888 10]
	fmt.Println("这是修改后的切片 s :>>>> ", s) // 这是修改后的切片 s :>>>>  [999 4 5 6 7 8 888]

	// 追加元素
	s = append(s, 333)
	fmt.Println("这是追加后的数组 a :>>>> ", a) // 这是追加后的数组 a :>>>>  [1 2 999 4 5 6 7 8 888 333]
	fmt.Println("这是追加后的切片 s :>>>> ", s) // 这是追加后的切片 s :>>>>  [999 4 5 6 7 8 888 333]

	// 追加元素到临界状态,继续追加,数组长度不够
	// 如果数组长度不够,go语言会自动申请一个新的数组,大小为原来切片容量的 2 倍
	// 并且把原来切片的值,复制到新数组上
	s = append(s, 777)
	fmt.Println("这是追加后的数组 a :>>>> ", a)         // 这是追加后的数组 a :>>>>  [1 2 999 4 5 6 7 8 888 333]
	fmt.Println("这是追加后的切片 s :>>>> ", s)         // 这是追加后的切片 s :>>>>  [999 4 5 6 7 8 888 333 777]
	fmt.Println("这是追加后的切片 长度 s :>>>> ", len(s)) // 这是追加后的切片 长度 s :>>>>  9
	fmt.Println("这是追加后的切片 容量 s :>>>> ", cap(s)) // 这是追加后的切片 容量 s :>>>>  16
	// 此时,切片与原来数组脱离,原来数组的变化不会影响新的切片
	s[0] = 555
	fmt.Println("这是原来的的数组 a :>>>> ", a) // 这是原来的的数组 a :>>>>  [1 2 999 4 5 6 7 8 888 333]
	fmt.Println("这是修改后的切片 s :>>>> ", s) // 这是修改后的切片 s :>>>>  [555 4 5 6 7 8 888 333 777]

}

【10】切片的函数传递

package main

import "fmt"

func main() {
	// 切片的函数传递
	// [1] 数组是值类型 , 切片是引用类型(指针)

	// go 语言中的参数传递是 copy 传递,把变量复制一份传入给函数中

	// 如果是值类型,就会复制一个新值,传入
	// 如果是引用类型,复制这个引用,传入(指向没变)

	// 如果是值类型,传入函数,修改后,不会影响原来的值
	// 如果是引用类型,传入函数,修改后,会影响原来的值

	// 创造数组
	var a [3]int = [3]int{7, 8, 9}

	// 调用函数 参数类型为 数组类型
	index1(a)
	fmt.Println("这是传入函数后的 a :>>>> ", a)
	// 这是参数类型为数组类型的 :>>>>  [999 8 9]
	// 这是传入函数后的 a :>>>>  [7 8 9]

	// 创造切片
	var s []int = a[:]

	// 调用函数 参数类型为 切片类型
	index2(s)
	fmt.Println("这是传入函数后的 a :>>>> ", a)
	fmt.Println("这是传入函数后的 s :>>>> ", s)
	// 这是参数类型为切片类型的 :>>>>  [999 8 9]
	// 这是传入函数后的 a :>>>>  [999 8 9]
	// 这是传入函数后的 s :>>>>  [999 8 9]
}

// 参数类型为 数组类型
func index1(a [3]int) {
	a[0] = 999
	fmt.Println("这是参数类型为数组类型的 :>>>> ", a)
}

// 参数类型为 切片类型
func index2(a []int) {
	a[0] = 999
	fmt.Println("这是参数类型为切片类型的 :>>>> ", a)
}

【11】多维切片

(1)通过数组初始化

package main

import "fmt"

func main() {
	// 多维切片
	// 定义多维切片
	var s [][]int
	fmt.Println("这是定义的多维切片 s :>>>> ", s) // 这是定义的多维切片 s :>>>>  []

	// 定义多维切片并初始化
	var b [][]int = [][]int{{1, 2, 3, 11, 22, 33}, {4, 5, 6}, {7, 8, 9}}
	fmt.Println("这是定义的多维切片 b :>>>> ", b)          // 这是定义的多维切片 b :>>>>  [[1 2 3 11 22 33] [4 5 6] [7 8 9]]
	fmt.Println("这是定义的多维切片 b 的长度 :>>>> ", len(b)) // 这是定义的多维切片 b 的长度 :>>>>  3
	fmt.Println("这是定义的多维切片 b 的容量 :>>>> ", cap(b)) // 这是定义的多维切片 b 的容量 :>>>>  3

	fmt.Println("这是定义的多维切片 b[0] :>>>> ", b[0])          // 这是定义的多维切片 b[0] :>>>>  [1 2 3 11 22 33]
	fmt.Println("这是定义的多维切片 b[0] 的长度 :>>>> ", len(b[0])) // 这是定义的多维切片 b[0] 的长度 :>>>>  6
	fmt.Println("这是定义的多维切片 b[0] 的容量 :>>>> ", cap(b[0])) // 这是定义的多维切片 b[0] 的容量 :>>>>  6
}

(2)通过make初始化

package main

import "fmt"

func main() {
	// 多维切片
	// 定义多维切片
	var s [][]int
	fmt.Println("这是定义的多维切片 s :>>>> ", s) // 这是定义的多维切片 s :>>>>  []

	// 定义多维切片并 通过 make 初始化
	var b [][]int = make([][]int, 3, 4)           // 内层的切片没有被初始化,只要使用内层切片,内层的所有切片都要被初始化
	fmt.Println("这是定义的多维切片 b :>>>> ", b)          // 这是定义的多维切片 b :>>>>  [[] [] []]
	fmt.Println("这是定义的多维切片 b 的长度 :>>>> ", len(b)) // 这是定义的多维切片 b 的长度 :>>>>  3
	fmt.Println("这是定义的多维切片 b 的容量 :>>>> ", cap(b)) // 这是定义的多维切片 b 的容量 :>>>>  4

	fmt.Println("这是定义的多维切片 b[0] :>>>> ", b[0])          // 这是定义的多维切片 b[0] :>>>>  []
	fmt.Println("这是定义的多维切片 b[0] 的长度 :>>>> ", len(b[0])) // 这是定义的多维切片 b[0] 的长度 :>>>>  0
	fmt.Println("这是定义的多维切片 b[0] 的容量 :>>>> ", cap(b[0])) // 这是定义的多维切片 b[0] 的容量 :>>>>  0

	// 修改内部的切片
	fmt.Println("这是内部的切片 :>>>> ", b[0]) // 这是内部的切片 :>>>>  []
	// 内部切片初始化
	//b[0][0] = 999                    // 由于内部的切片未被初始化,所以没法使用, 会报空指针错误
	//fmt.Println("这是修改后的 s :>>> ", b) // panic: runtime error: index out of range [0] with length 0

	// 先初始化内部切片,再使用
	b[0] = make([]int, 4, 5) // 对内层切片初始化
	b[0][0] = 999
	fmt.Println("这是修改后的 s :>>> ", b) // 这是修改后的 s :>>>  [[999 0 0 0] [] []]

	// 取内部切片的容量以外的值
	// 切片越界 , 虽然容量是 5 但是还没使用到,就不能被取出来
	fmt.Println("这是 b[0][5] :>>> ", b[0][5]) // panic: runtime error: index out of range [5] with length 4
}
package main

import "fmt"

func main() {
	//
	var b []int = make([]int, 3, 4)     // 切片根据索引下标取值,但是只能取到长度 -1 的大小
	fmt.Println("这是创建的 切片 b :>>>> ", b) // 这是创建的 切片 b :>>>>  [0 0 0]
	b = append(b, 99)
	fmt.Println("这是追加后的 切片 b :>>>> ", b)       // 这是追加后的 切片 b :>>>>  [0 0 0 99]
	fmt.Println("这是追加后的 切片 b[3] :>>>> ", b[3]) // 这是追加后的 切片 b :>>>>  99
}

【12】循环多维切片

package main

import "fmt"

func main() {
	// 循环多维切片 (基于索引,基于迭代)

	// 定义多维切片
	var b [][]int = [][]int{{11, 22}, {4, 5, 6}, {77, 8, 9, 10}}
	fmt.Println("这是创建的多维切片 :>>>> ", b) // 这是创建的多维切片 :>>>>  [[11 22] [4 5 6] [77 8 9 10]]
	// 基于索引循环多维切片
	for i := 0; i < len(b); i++ {
		fmt.Println("这是外部循环 切片内部的值 :>>>> ", b[i])
		for j := 0; j < len(b[i]); j++ {
			fmt.Println("这是内部循环 切片内部的值 :>>>> ", b[i][j])
		}
	}
	//这是外部循环 切片内部的值 :>>>>  [11 22]
	//这是内部循环 切片内部的值 :>>>>  11
	//这是内部循环 切片内部的值 :>>>>  22
	//这是外部循环 切片内部的值 :>>>>  [4 5 6]
	//这是内部循环 切片内部的值 :>>>>  4
	//这是内部循环 切片内部的值 :>>>>  5
	//这是内部循环 切片内部的值 :>>>>  6
	//这是外部循环 切片内部的值 :>>>>  [77 8 9 10]
	//这是内部循环 切片内部的值 :>>>>  77
	//这是内部循环 切片内部的值 :>>>>  8
	//这是内部循环 切片内部的值 :>>>>  9

	// 基于迭代多维切片
	fmt.Println("----- 基于迭代多维切片 -----")
	for _, value := range b {
		fmt.Println("这是外部循环切片内部的值 :>>>> ", value)
		for _, val := range value {
			fmt.Println("这是内部循环切片内部的值 :>>>> ", val)
		}
	}
	//这是外部循环切片内部的值 :>>>>  [11 22]
	//这是内部循环切片内部的值 :>>>>  11
	//这是内部循环切片内部的值 :>>>>  22
	//这是外部循环切片内部的值 :>>>>  [4 5 6]
	//这是内部循环切片内部的值 :>>>>  4
	//这是内部循环切片内部的值 :>>>>  5
	//这是内部循环切片内部的值 :>>>>  6
	//这是外部循环切片内部的值 :>>>>  [77 8 9 10]
	//这是内部循环切片内部的值 :>>>>  77
	//这是内部循环切片内部的值 :>>>>  8
	//这是内部循环切片内部的值 :>>>>  9
	//这是内部循环切片内部的值 :>>>>  10
}

【13】copy

package main

import "fmt"

func main() {
	// copy : 把一个切片,复制到另一个切片上
	var a [20]int = [20]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	fmt.Println("这是创建的切片 a :>>>> ", a) // 这是创建的切片 a :>>>>  [1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0]

	// 切片
	b := a[:3]
	fmt.Println("这是创建的切片 b :>>>> ", b) // 这是创建的切片 b :>>>>  [1 2 3]

	// 只要使用 切片 b , 底层基于了一个很大的数组 , 内存的占用就很高
	// 把 切片 b ,copy 到另一个基于小数组的切片上

	// 【1】两个切片一样长,可以直接copy
	c := make([]int, 3, 3)
	fmt.Println("这是创建的新切片 c :>>>> ", c) // 这是创建的新切片 c :>>>>  [0 0 0]

	copy(c, b)
	fmt.Println("这是 copy 后的新切片 c :>>>> ", c) // 这是 copy 后的新切片 c :>>>>  [1 2 3]

	// 【2】两个切片不一样长 , 以多的为准,不够则 0 补齐
	d := make([]int, 5, 5)
	fmt.Println("这是创建的新切片 d :>>>> ", d) // 这是创建的新切片 d :>>>>  [0 0 0 0 0]

	copy(d, b)
	fmt.Println("这是 copy 后的新切片 d :>>>> ", d) // 这是 copy 后的新切片 d :>>>>  [1 2 3 0 0]

	// 【3】两个切片不一样长 , 以少的为准,有几个 copy 几个
	e := make([]int, 2, 2)
	fmt.Println("这是创建的新切片 e :>>>> ", e) // 这是创建的新切片 e :>>>>  [0 0]

	copy(e, b)
	fmt.Println("这是 copy 后的新切片 e :>>>> ", e) // 这是 copy 后的新切片 e :>>>>  [1 2]
}