[TOC]
# slice
**注意,切片代表的窗口是無法向左擴展的**
**順便提一下把切片的窗口向右擴展到最大的方法。對于s4來說,切片表達式s4\[0:cap(s4)\]就可以做到**
一個切片的容量可以被看作是透過這個窗口最多可以看到的底層數組中元素的個數
切片并不是數組或數組指針,它通過內部指針和相關屬性引用數組片段,以實現變長方案
slice并不是真正意義上的動態數組,而是一個引用類型.slice總是指向一個底層array, slice的聲明也可以像array一樣,只是不需要長度
可以把切片看做是對數組的一層簡單的封裝,因為在每個切片的底層數據結構中,一定會包含一個數組。數組可以被叫做切片的底層數組,而切片也可以被看作是對數組的某個連續片段的引用。
在這種情況下,切片的容量實際上代表了它的底層數組的長度
~~~
[low:high:max]
low起點
high終點(不包括此下標)
cap = max-low, 容量
~~~

~~~
func main() {
a := []int{1, 2, 3, 4, 5}
s := a[0:3:5]
fmt.Println("s = ", s)
//長度
fmt.Println("len(s) = ", len(s))
//容量
fmt.Println("cap(s) = ", cap(s))
}
~~~
輸出
~~~
s = [1 2 3]
len(s) = 3
cap(s) = 5
~~~
多維的切片
~~~
[][]int{{10,20},{30}}
~~~
## 數組和切片的區別
~~~
func main() {
a := [5]int{}
fmt.Printf("len = %d, cap = %d\n", len(a), cap(a))
s := []int{}
fmt.Println(len(s), cap(s))
s = append(s, 11)
fmt.Printf("append: len = %d, cap = %d\n", len(s), cap(s))
}
~~~
輸出
~~~
len = 5, cap = 5
0 0
append: len = 1, cap = 1
~~~
## 切片的創建
~~~
func main() {
//自動推導類型,同時初始化
s1 := []int{1, 2, 3, 4}
fmt.Println("s1 = ", s1)
//借助make函數,格式make(切片類型,長度,容量)
s2 := make([]int, 5, 10)
fmt.Println(len(s2), cap(s2))
//沒有指定容量,容量和長度一樣
s3 := make([]int, 5)
fmt.Println(len(s3), cap(s3))
}
~~~
## 切片的截取

## 切片和底層數組的關系
會改變底層數組
~~~
func main() {
a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
//新切片
s1 := a[2:5]
s1[1] = 666
fmt.Println("s1 = ", s1)
fmt.Println("a = ", a)
//另外切片
s2 := s1[2:7]
s2[2] = 777
fmt.Println("s2 = ", s2)
fmt.Println("a = ", a)
}
~~~
輸出
~~~
s1 = [2 666 4]
a = [0 1 2 666 4 5 6 7 8 9]
s2 = [4 5 777 7 8]
a = [0 1 2 666 4 5 777 7 8 9]
~~~
## 易錯
一個切片是以另一個切片為基礎切,容量一樣那么都是指向同一個東西
~~~
func main() {
data := []string{"red", "1", "black", "1", "pink", "red"}
out := data[:1]
for _, word := range data {
fmt.Println("-----------")
i:=0
//比較取出的word是否在out中存在
for ; i<len(out); i++ {
if word == out[i] {
fmt.Println(len(out))
break
}
}
if i== len(out) {
out = append(out, word)
fmt.Println(word)
}
}
fmt.Println(data)
fmt.Println(out)
}
~~~
## append函數
會智能的底層數組的容量增長,一旦超過原底層數組容量,通常以2倍容量重新分配底層數組,并復制原來的數據
~~~
func main() {
data := []string{"red", "1", "black", "1", "pink"}
fmt.Printf("%v\n", data)
out := data[:0]
fmt.Printf("%v\n", out)
for _, str := range data{
if str != "1" {
out = append(out, str)
}
}
fmt.Printf("%v\n", data) //感覺奇怪
fmt.Printf("%v\n", out)
//[red 1 black 1 pink]
//[]
//[red black pink 1 pink]
//[red black pink]
}
~~~
如果不想里面有空的元素,就make的len為0,cap為0
~~~
slice := make([]string, 0)
slice = append(slice, "111")
slice = append(slice, "222")
slice = append(slice, "33")
for _, data := range slice {
fmt.Println("data----", data)
}
~~~
`slice:=append([]int{1,2,3},[]int{4,5,6}...)`
`fmt.Println(slice)//[1 2 3 4 5 6]`
* 還有種特殊用法,將字符串當作\[\]byte類型作為第二個參數傳入
## copy
copy會把一些位置替換
~~~
func main() {
srcSlice := []int{1, 2}
dstSlice := []int{6, 6, 6, 6, 6}
copy(dstSlice, srcSlice)
fmt.Println("dst = ", dstSlice)
}
~~~
輸出
~~~
dst = [1 2 6 6 6]
~~~
## 作為函數參數
是引用傳遞,里面改了,外面也一樣會改
~~~
complexArray1 := [3][]string{
[]string{"d", "e", "f"},
[]string{"g", "h", "i"},
[]string{"j", "k", "l"},
}
~~~
變量complexArray1是\[3\]\[\]string類型的,也就是說,雖然它是一個數組,但是其中的每個元素又都是一個切片。這樣一個值被傳入函數的話,函數中對該參數值的修改會影響到complexArray1本身嗎?
分2種情況,若是修改數組中的切片的某個元素,會影響原數組。若是修改數組的某個元素即a\[1\]=\[\]string{"x"}就不會影響原數組。謹記Go中都是淺拷貝,值類型和引用類型的區別
## nil
目前已知只有`var s []int`這1種方法才是nil slice。其他情況都不是,因為只有no underlying array才是nil slice
下面幾種方法都不是nil slice
1. `s := []int{}`不是nil
2. 刪除所有元素也不算是nil,如
~~~
sli = sli[:cap(sli)]
sli = sli[len(sli):]
~~~
3. 用`make([]int, 0, 0)`也不是nil
~~~
package main
import "fmt"
func main() {
var a []int
fmt.Println("a:", a, len(a), cap(a))
b := []int{}
fmt.Println("b:", b, len(b), cap(b))
c := make([]int, 0, 0)
fmt.Println("c:", c, len(c), cap(c))
d := []int{2, 3, 5, 7, 11, 13}
d = d[:cap(d)]
d = d[len(d):]
fmt.Println("d:", d, len(d), cap(d))
if a == nil {
fmt.Println("a is nil")
}
if b == nil {
fmt.Println("b is nil")
}
if c == nil {
fmt.Println("c is nil")
}
if d == nil {
fmt.Println("d is nil")
}
}
~~~
## 嵌套
slice可以嵌套包含slice,并且可以嵌套多層。也可以叫做多維slice。另外,array也支持多維array(這里就不提了)
嵌套一層
~~~
board1 := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
~~~
**支持簡寫**
比如上面這個例子可以改為
~~~
b := [][]string{
{"_", "_", "_"},
{"_", "_", "_"},
{"_", "_", "_"},
}
~~~
嵌套兩層
~~~
board2 := [][][]string{
[][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
},
[][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
},
[][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
},
}
~~~
賦值
~~~
board1[0][0] = "X"
board2[0][0][0] = "Y"
~~~
通過嵌套實現了高級數據結構,比如python中列表嵌套字典嵌套列表等等
- 基礎
- 簡介
- 主要特征
- 變量和常量
- 編碼轉換
- 數組
- byte與rune
- big
- sort接口
- 和mysql類型對應
- 函數
- 閉包
- 工作區
- 復合類型
- 指針
- 切片
- map
- 結構體
- sync.Map
- 隨機數
- 面向對象
- 匿名組合
- 方法
- 接口
- 權限
- 類型查詢
- 異常處理
- error
- panic
- recover
- 自定義錯誤
- 字符串處理
- 正則表達式
- json
- 文件操作
- os
- 文件讀寫
- 目錄
- bufio
- ioutil
- gob
- 棧幀的內存布局
- shell
- 時間處理
- time詳情
- time使用
- new和make的區別
- container
- list
- heap
- ring
- 測試
- 單元測試
- Mock依賴
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 詳解
- plugin包
- 信號
- goto
- 協程
- 簡介
- 創建
- 協程退出
- runtime
- channel
- select
- 死鎖
- 互斥鎖
- 讀寫鎖
- 條件變量
- 嵌套
- 計算單個協程占用內存
- 執行規則
- 原子操作
- WaitGroup
- 定時器
- 對象池
- sync.once
- 網絡編程
- 分層模型
- socket
- tcp
- udp
- 服務端
- 客戶端
- 并發服務器
- Http
- 簡介
- http服務器
- http客戶端
- 爬蟲
- 平滑重啟
- context
- httptest
- 優雅中止
- web服務平滑重啟
- beego
- 安裝
- 路由器
- orm
- 單表增刪改查
- 多級表
- orm使用
- 高級查詢
- 關系查詢
- SQL查詢
- 元數據二次定義
- 控制器
- 參數解析
- 過濾器
- 數據輸出
- 表單數據驗證
- 錯誤處理
- 日志
- 模塊
- cache
- task
- 調試模塊
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密碼
- 對稱加密
- 非對稱加密
- 單向散列函數
- 消息認證
- 數字簽名
- mysql優化
- 常見錯誤
- go run的錯誤
- 新手常見錯誤
- 中級錯誤
- 高級錯誤
- 常用工具
- 協程-泄露
- go env
- gometalinter代碼檢查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高編譯
- go get
- 代理
- 其他的知識
- go內存對齊
- 細節總結
- nginx路由匹配
- 一些博客
- redis為什么快
- cpu高速緩存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密碼加密解密
- for 循環迭代變量
- 備注
- 垃圾回收
- 協程和纖程
- tar-gz
- 紅包算法
- 解決golang.org/x 下載失敗
- 逃逸分析
- docker
- 鏡像
- 容器
- 數據卷
- 網絡管理
- 網絡模式
- dockerfile
- docker-composer
- 微服務
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell調用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb