多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] 上一章讲的是 `array` 数组,实际使用频率不是很高。因为它是不能扩容的。定义的时候写3的值,就是固定三个值。所以才有本文介绍的 `slice` 切片类型。 切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一个引用类型,它的内部结构包含 `地址` 、 `长度` 和 `容量` 。 ## 切片定义 ```go // (1) 定义并初始化 var s1 = []string{"jiaxzeng"} fmt.Printf("s1: %v\n", s1) // (2) 基于数组切片 var a1 = [5]int{1, 2, 3, 4, 5} // 切片操作都是左闭右开 [) // 从a1索引1开始切到2。 s2 := a1[1:3] // 从a1索引0开始切到2,冒号前面空,则说明从开头开始 s3 := a1[:3] // 从a1索引3开始切到结尾,冒号后面空,则说明切到最后。包含最后一个 s4 := a1[3:] fmt.Printf("s2: %d, type: %T\n", s2, s2) fmt.Printf("s3: %d, type: %T\n", s3, s3) fmt.Printf("s4: %d, type: %T\n", s4, s4) // 运行结果: // s1: [jiaxzeng] // s2: [2 3], type: []int // s3: [1 2 3], type: []int // s4: [4 5], type: []int ``` ## make定义切片 如果需要动态的创建一个切片,我们就需要使用内置的make()函数 make函数定义切片语法:`make(Type, len, cap)` ```go s5 := make([]int, 3, 5) fmt.Printf("s5: %d, type: %T, len: %d, cap: %d\n", s5, s5, len(s5), cap(s5)) // 运行结果: // s5: [0 0 0], type: []int, len: 3, cap: 5 ``` ## 切片的地址、长度和容量 可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量,使用 `fmt.Printf("%T", variable)` 打印地址 示例一: ```go s6 := []string{"beijing", "guangdong", "shagnhai"} for i := 0; i < len(s6); i++ { fmt.Printf("s6[%d]: %s, pointer: %p\n", i, s6[i], &s6[i]) } fmt.Printf("s6: %v, len: %d, cap: %d, pointer: %p\n", s6, len(s6), cap(s6), s6) // 运行结果: // s6[0]: beijing, pointer: 0xc000100150 // s6[1]: guangdong, pointer: 0xc000100160 // s6[2]: shagnhai, pointer: 0xc000100170 // s6: [beijing guangdong shagnhai], len: 3, cap: 3, pointer: 0xc000100150 ``` 示例二: ```go var a2 = [5]int{1, 2, 3, 4, 5} for i := 0; i < len(a2); i++ { fmt.Printf("a2[%d]: %d, pointer: %p\n", i, a2[i], &a2[i]) } s7 := a2[:3] fmt.Printf("s7: %v, len: %d, cap: %d, pointer: %p\n", s7, len(s7), cap(s7), s7) // 运行结果: // a2[0]: 1, pointer: 0xc0000ba000 // a2[1]: 2, pointer: 0xc0000ba008 // a2[2]: 3, pointer: 0xc0000ba010 // a2[3]: 4, pointer: 0xc0000ba018 // a2[4]: 5, pointer: 0xc0000ba020 // s7: [1 2 3], len: 3, cap: 5, pointer: 0xc0000ba000 ``` 示例三: ```go var a3 = [5]int{1, 2, 3, 4, 5} for i := 0; i < len(a3); i++ { fmt.Printf("a3[%d]: %d, pointer: %p\n", i, a3[i], &a3[i]) } s8 := a3[2:4] fmt.Printf("s8: %v, len: %d, cap: %d, pointer: %p\n", s8, len(s8), cap(s8), s8) // 运行结果: // a3[0]: 1, pointer: 0xc0000ba000 // a3[1]: 2, pointer: 0xc0000ba008 // a3[2]: 3, pointer: 0xc0000ba010 // a3[3]: 4, pointer: 0xc0000ba018 // a3[4]: 5, pointer: 0xc0000ba020 // s8: [3 4], len: 2, cap: 3, pointer: 0xc0000ba010 ``` ## 切片原理 切片是一个引用类型,本质就是对底层数组的封装。它的内部结构包含 `地址` 、 `长度` 和 `容量` 。 引用上面三种情况,相应示意图如下: 示例一: ![](https://img.kancloud.cn/94/28/942876d067c1aa93753358132c59b390_1017x447.png) 示例二: ![](https://img.kancloud.cn/b2/d0/b2d02f5c57e2bf70d7270c584262be6a_1334x402.png) 示例三: ![](https://img.kancloud.cn/a0/2c/a02c02a1f619a2a9f322205d3d0c2a4d_1336x411.png) >[info] 总结: > 1. 长度是 切片元素个数 > 2. 容量是 切片地址指向的底层数组下标到数组结尾