1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
| package main
import "fmt"
func main() {
var nums []int // var nums []int = nil
// nil切片 赋值为nil
fmt.Printf("%T, %v, %v\n", nums, nums, nums == nil) // []int, [], true
// 内存 暂时不关注
// 字面量
nums = []int{} // 空切片 不等于nil
fmt.Printf("%T, %v, %v\n", nums, nums, nums == nil) // []int, [], false
nums = []int{1, 2, 3, 4}
fmt.Println(nums)
nums = []int{1, 2, 3, 4, 5, 6, 7} // 长度可变
fmt.Println(nums)
nums = []int{1: 1, 10: 11} // [0 1 0 0 0 0 0 0 0 0 11]
fmt.Println(nums)
// make([]int, length)
// length: 切片元素的数量
// 赋值有5个元素的int类型零值组成的切片
nums = make([]int, 5)
fmt.Println(nums)
// make([]int, length, cap)
// length: 元素数量
// cap: 容量 => 底层数组的长度
// slice底层 => 数组存储 数组长度固定 当length == cap 再添加本素 重新申请内存 拷贝 释放旧数组内存
// 切片长度增长(元素数量) 增长 => 底层数组长度不够怎么办 => 重新生成一个新的可以容纳更多元素的数组(拷贝原来数组中的元素)
// 底层数组原长度:10 增加一个元素 增长:10 底层数组现长度:20
// 选择的元素:11 剩9个没有使用
nums = make([]int, 3, 10)
fmt.Println(nums)
// 切片操作 => 数组 字符串 切片
numArray := [5]int{1, 3, 5, 7, 9}
fmt.Printf("%T, %v\n", numArray[1:3], numArray[1:3])
// [start:end] start <= end <= length
// 数组切片赋值给切片
nums = numArray[1:3]
fmt.Println(nums)
// 容量 cap()
nums = numArray[0:4]
fmt.Printf("%T, %v, %v, %v\n", nums, nums, len(nums), cap(nums)) // []int, [1 3 5 7], 4, 5
nums = numArray[1:]
fmt.Printf("%T, %v, %v, %v\n", nums, nums, len(nums), cap(nums)) // []int, [3 5 7 9], 4, 4
// 切片的切片操作
fmt.Printf("%T, %v\n", nums[1:3], nums[1:3])
// 切片的赋值方式
// 1. 零值 nil切片
// 2. 字面量
// 3. make函数(指定容量 不指定容量)
// 4. 切片操作(数组切片 切片切片)
// 操作:不能进行== 和 !=运算
// 函数: len cap append copy
// 元素的访问和修改: 通过索引 slice[i];slice[i] = value
// 切片操作:
// slice[start:end:cap_end] start <= end <= cap_end <= cap(slice)
// array[start:end:cap_end] start <= end <= cap_end <= len(array)
// 切片底层:
// 数组地址
// 容量
// 长度
// 长度:len() 容量:cap()
nums = []int{}
fmt.Println(len(nums), cap(nums))
nums = []int{1, 2, 3}
fmt.Println(len(nums), cap(nums))
nums = make([]int, 10)
fmt.Println(len(nums), cap(nums)) // 10, 10
nums = make([]int, 0, 10)
fmt.Println(len(nums), cap(nums)) // 0, 10
nums = numArray[1:3] // cap = length - start
fmt.Println(numArray) // [1 3 5 7 9]
fmt.Println(len(nums), cap(nums))
// 元素的访问和修改
fmt.Println(nums)
nums[0] = 100 // 索引的范围:0,length-1 or 0,cap-1?
// fmt.Println(nums[1])
// fmt.Println(nums[2]) // 运行时报错 索引范围是0,length-1
// 遍历
for i := 0; i < len(nums); i++ {
fmt.Printf("%v: %v\n", i, nums[i])
}
for index, value := range nums {
fmt.Printf("%v: %v\n", index, value)
}
// 添加元素
nums = append(nums, 1) // 末尾追加
fmt.Println(nums)
nums = append(nums, 100, 2, 3) // 追加多个元素
fmt.Println(nums)
// 删除元素
// go中没有直接删除元素的方法 需要用到: 切片 + 解包
// 删除索引为0的(首)
nums = nums[1:len(nums)]
fmt.Println(nums)
// 删除索引为length-1的(尾)
nums = nums[:len(nums)-1]
fmt.Println(nums)
// 删除中间的(索引为i)
// [0:i] + [i+1:len(nums)]
// 1. 循环append
// prefix := nums[0:1]
// suffix := nums[2:len(nums)]
// fmt.Println(prefix, suffix)
// for _, value := range suffix {
// prefix = append(prefix, value)
// }
// fmt.Println(prefix)
// 2. 解包方式 go把切片元素展开 语法糖
fmt.Println(append(nums[0:1], nums[2:len(nums)]...))
// start:end start = 0 => [:end] 省略
// start:end end = length => [start:]
// 容量
// 增长规则: <= 1024 n => 2*n
// > 1024 n => n*(1+~0.25)
nums = []int{}
fmt.Println(len(nums), cap(nums)) // 0 0
nums = append(nums, 1)
fmt.Println(len(nums), cap(nums)) // 1 1
nums = append(nums, 2)
fmt.Println(len(nums), cap(nums)) // 2 2
nums = append(nums, 3)
fmt.Println(len(nums), cap(nums)) // 3 4
nums = append(nums, 4)
fmt.Println(len(nums), cap(nums)) // 4 4
nums = append(nums, 5)
fmt.Println(len(nums), cap(nums)) // 5 8
// 如果可以预期切片的最大长度 可以通过make函数指定cap容量 减少申请内存的损耗
// start:end:cap_end
numArray = [5]int{1, 3, 5, 7, 8}
nums = numArray[1:3] // len = end - start; cap = len(底层数组) - start
nums = append(nums, 1000) // 切片会共享底层数组
fmt.Println(numArray) // [1 3 5 1000 8]
fmt.Println(nums) // [3 5 1000]
fmt.Println("#########")
nums = numArray[3:5] // [1000 8]
nums = append(nums, 3)
fmt.Println(numArray) // [1 3 5 1000 8]
fmt.Println(nums) // [100 8 3]
// [start:end:cap_end] 切片可以指定cap的位置(限制cap)
// end <= cap_end <= 底层数组的长度
nums = numArray[1:3:4] // cap = cap_end - start
fmt.Println(len(nums), cap(nums)) // 2 2
nums = append(nums, 999)
fmt.Println(nums)
fmt.Println(numArray)
// len和cap一样 append会触发扩容 扩容不会影响原来的底层数组 生成新的底层数组
// 否则 会影响底层数组(改变底层数组的值)
// 总结:如果使用数组来生成切片 那么操作切片(append扩容)根据容量的情况 会影响底层数组 或是生成新的底层数组
// 切片的切片操作
// [start:end] start <= end <= cap(nums); end小于等于容量cap
fmt.Println("###########")
nums = make([]int, 3, 10)
nums[0] = 1
nums[1] = 2
nums[2] = 3
fmt.Println(nums)
numsSlice := nums[1:5] // [2 3 0 0]
fmt.Println(numsSlice)
fmt.Println(len(numsSlice), cap(numsSlice)) // 1, 9 仍然共享底层数组
numsSlice = append(numsSlice, 100)
fmt.Println(nums) // numsSlice扩容了一个元素100 nums值改变 [1 2 3] => [1 2 100] 原因:共享了底层数组
// 限定cap
numsSlice = nums[1:2:2]
fmt.Println(numsSlice)
fmt.Println(len(numsSlice), cap(numsSlice))
// copy函数(dst, src) 后面的切片拷贝到前面的切片
// copy:只赋值索引相同的元素 复制值不够:保留 复制只太多:剔除 并不扩容
dst := make([]int, 3)
src := []int{2, 3, 4}
// len(src) == len(dst)
fmt.Println(src, dst)
copy(dst, src)
fmt.Println(src, dst) // [2 3 4] [2 3 4]
// len(dst) > len(src) 保留未被覆盖部分
src = []int{200, 300}
copy(dst, src)
fmt.Println(src, dst) // [200 300] [200 300 4]
// len(dst) < len(src)
src = []int{1000, 2000, 3000, 4000}
copy(dst, src)
fmt.Println(src, dst) // [1000 2000 3000 4000] [1000 2000 3000] 长度并不会在拷贝过程中进行调整
// 通过copy来删除索引为i的元素
nums = []int{1, 2, 3, 4, 5}
// 删除索引为2的
fmt.Println(nums[2:]) // [3 4 5]
fmt.Println(nums[3:]) // [4 5]
copy(nums[2:], nums[3:])
fmt.Println(nums[:len(nums)-1]) // [1 2 4 5 5]
}
|