## 声明
数组:
```go
var array [size] string
```
切片:
```go
var slice [] string
```
**差异**:数组的声明需要指定“**size**”,如果不指定就是为切片(slice)
## 初始化
**数组:**
```go
var array1 = [3] string{"one", "two", "three"}
var array2 = [...] string{"one", "two", "three"}
array3 := [...] string{"one", "two", "three"} // 推荐:无需通过var声明
```
**切片:**
```go
var slice [] string
slice = make([]string, 5, 5) // 指定长度为5,容量为5的切片
slice = make([]string,5) // 指定长度为5,容量为5的切片
slice2 := [] string{"one", "two", "three"} // 推荐:无需通过var声明
```
注:大部分情况下如果不知道切片长度,只要声明,无需初始化,单需要往切片增加数据是,通过append添加(声明的切面默认值是nil,但是append并不会异常)
## 常用操作
### 读取
**数组**
数组一般是在for循环中通过索引,或是range 直接读取:
```go
aa := [5] string{}
for i, a := range aa { // aa的副本
fmt.Println("i= ", i, ", s=", a)
}
for i:=0; i< len(aa); i++ {
fmt.Println("i= ", i, ", s=", aa[i])
}
```
注意:
range 的是数组的副本,也是就是说会把aa拷贝一份,并且读取出来的项也是对应的副本,所以对项的修改是不会影响原有的数组,当aa比较大的时候会影响性能,所以可以采用读取数组指针的方式来优化:
```go
for i, a := range &aa { // 这里拷贝的会是aa的指针
fmt.Println("i= ", i, ", s=", a)
}
```
**切片**
切片的读取和数组类似一般是在for循环中通过索引,或是range 直接读取:
```go
aa := [] string{“hello”, "world"}
for i, a := range aa { // aa副本,但是由于切片时特殊的结构体,并不会保存整个数组,而是数据组第一个元素的地址,所以就算副本对性能也不会有太大影响
fmt.Println("i= ", i, ", s=", a)
}
for i:=0; i< len(aa); i++ {
fmt.Println("i= ", i, ", s=", aa[i])
}
```
注意:
切片和数组存在一些差异,切片range的时候拷贝的是slice的数据,底层还是共享数组,所以修改的时候回会影响原来slice
### 添加
数组:
一个数组中的元素个数总是恒定的,我们无法向其中添加元素,也无法从其中删除元素。但是元素可以通过索引修改值
```go
aa := [5] string{}
aa[0] = "张三"
```
切片:
切片的底层实际上也是关联一个数组,所以如果新增元素超过数组的容量,内部会重新开辟一个数组大于(小于1024翻倍,大于增加25%)当前的数组
**头部插入**
```go
aa := [] string{"张三", "李四"}
result := append([]string{"王五"}, aa...) // result = {"王五", "张三", "李四"}
```
**尾部追加**
```go
aa := [] string{"张三", "李四"}
result := append(aa, "王五", "张飞") // 可以追加多个,result = { "张三", "李四", "王五", "张飞"}
```
### **删除**
删除第i个元素
```go
// 第一种方法(保持剩余元素的次序):
s = append(s[:i], s[i+1:]...)
// 第二种方法(保持剩余元素的次序):
s = s[:i + copy(s[i:], s[i+1:])]
// 上面两种方法都需要复制len(s)-i-1个元素。
// 第三种方法(不保持剩余元素的次序):
s[i] = s[len(s)-1]
s = s[:len(s)-1]
```
条件删除:keep判断条件,需要保留的返回true
```go
func filter(data [] *T, keep func(item *T) bool, clear bool) [] *T{
result:=data[:0] // 复用data内存,无需另外开辟。(注:会修改原切片共享数组内容)
for _, d := range data {
if keep(d) {
result = append(result, d)
}
}
if clear { // 避免暂时性的内存泄露。
temp := data[len(result):]
for i := range temp {
temp[i] = nil // t0是类型T的零值
}
}
return result
}
```
### 拷贝
拷贝b切片
**方法1**
```
var b [] T
if a!=nil{
b = make([]T, len(a))
copy(b, a)
}
```
**方法2**
```go
var b [] T
if a!=nil{
b = append([]T(nil), a...)
}
```
**方法3(最简洁)**
```go
b = append(a[:0:0], a...)
```
这里就利用了当a为nil的是时候,a[:0:0]并不会报错,仍然会是nil且a[:0:0] == nil为true
我的博客:[Go数组&切片使用 | 艺术码农的小栈](https://itart.cn/blogs/2021/practice/go-array-slice-demo.html)
有疑问加站长微信联系(非本文作者))