> go语言github项目:https://github.com/minibear2333/how_to_code
[TOC]
### 先来看看Golang中的数组
其实在[循环](https://mp.weixin.qq.com/s?__biz=MzAxOTc1OTY4NA==&mid=2650856000&idx=3&sn=1a6cdbf89fcfa4cd7fa0d66a7d1de2e2&chksm=80366d6bb741e47d96d1706713198ce6840a87576bb97ffd5b3c3cecbf964509b607950b0d23&scene=21#wechat_redirect)那一节用到过数组,我快速介绍一下。
- 数组中是固定长度的连续空间(内存区域)
- 数组中所有元素的类型是一样的
```go
var a1 [10]int
//初始化数组
var b1 = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
```
**多维数组**
```go
//声明二维数组,只要 任意加中括号,可以声明更多维,相应占用空间指数上指
var arr [3][3]int
//赋值
arr = [3][3]int{
{1, 2, 3},
{2, 3, 4},
{3, 4, 5},
}
```
### 何谓切片?
类比`c`语言,一个`int`型数组`int a[10]`,`a`的类型是`int*`,也就是整型指针,而`c`语言中可以使用`malloc()`动态的分配一段内存区域,`c++`中可以用`new()`函数。例如:
```go
int* a = (int *)malloc(10);
int* b = new int(4);
```
此时,`a`和`b`的类型也是`int*`,`a`和`b`此时分配内存的方式类似于`go`语言中的切片。
`Go`的数组和切片都是从`c`语言中延续过来的设计。
### 有何不同?
```go
var sliceTmp []int
```
可以看到和`c`不同的是,`go`可以声明一个空切片(默认值为`nil`),然后再增加值的过程中动态的改变切片值大小。
### 怎么动态增加?
增加的方式只有一种,使用`append`函数追加。
```go
sliceTmp = append(sliceTmp, 4)
sliceTmp = append(sliceTmp, 5)
```
每个切片有长度`len`和容量`cap`两个概念,长度是我们最熟知的,和数组长度相同,可以直接用来遍历。
```go
for _,v := range slice1{
fmt.Println(v)
}
```
用切糕来对比

每个切片,在声明或扩建时会分配一段连续的空间,称为容量`cap`,是不可见的;真正在使用的只有一部分连续的空间,称为长度`len`,是可见的。
每次`append`时,如果发现`cap`已经不足以给`len`使用,就会重新分配原`cap`两倍的容量,把原切片里已有内容全部迁移过去。
新分配的空间也是连续的,不过不一定直接在原切片内存地址处扩容,也有可能是新的内存地址。
### 切片的长度与容量,len cap append copy
```go
slice1 := []int{1, 2, 3}
```
普通切片的声明方式,长度和容量是一致的。
```
len=3 cap=3 slice=[1 2 3]
```
当然,控制权在我们手上,我们可以自己控制长度和容量,
```go
slice1 = make([]int, 3, 5) // 3 是长度 5 是容量
```
输出
```
len=3 cap=5 slice=[0 0 0]
```
尝试使用一般的方式扩容
```go
slice1[len(slice1)] = 4
//报错 panic: runtime error:
//index out of range [3] with length 3
```
这种方式是会报错的,虽然容量是 5 ,但是数组长度是3,这里是以长度为准,而不是容量,`append`内部如果超过容量相当于创建了一个新数组,每个新数组都是定长的,只不过外部是切片。
尝试扩容
```go
slice1 = append(slice1, 4)
```
输出,可以发现`len`扩容了!
```
len=4 cap=5 slice=[0 0 0 4]
```
让我们连续扩容,让容量超过`5`
```go
slice1 = append(slice1, 5)
slice1 = append(slice1, 6) // 到这里长度超过了容量,容量自动翻倍为 5*2
```
输出
```
len=6 cap=10 slice=[0 0 0 4 5 6]
```
上面的过程,我 用自己的代码模拟一遍
```go
// 上面容量自动翻倍的过程可以看作和下面一致
slice1 = make([]int, 3, 5) // 3 是长度 5 是容量
slice1 = append(slice1, 4)
slice1 = append(slice1, 5)
// 长度不变,容量自动翻倍为 5*2
slice2 := make([]int, len(slice1),
(cap(slice1))*2)
// 拷贝 slice1 的内容到 slice2
// 注意是后面的拷贝给前面
copy(slice2, slice1)
slice2 = append(slice2, 6)
```
**所以,你理解容量,长度的概念了吗?**
- 安装与下载
- 投稿大纲
- 第一章、跑起来
- 为什么要学 go 语言?
- 让你的 Golang 项目在 IDE 里跑起来
- 第一个 go 程序
- go mod最佳实践
- 第二章、语言基础
- 声明【变量】的各种方式
- 常量+各种类型转换
- switch和type switch
- 循环语句的多种形式、死循环、break/continue
- range深度解析
- 第三章、函数和容器
- 函数简单使用和基本知识解析
- 匿名函数和闭包
- 可变参数
- 集合(map)
- 数组和切片
- 切片知识补充
- 第四章、指针、结构体、接口和异常处理
- 指针讨论
- 结构体
- 接口与多态
- 异常处理
- 第五章、再学一点运用自如
- 其他常用操作
- Go文件操作大全
- Go代码基本标准规范
- 切片排序sort包的使用
- Golang打镜像Dockerfile的写法
- 等待goroutine完成任务,循环中使用goroutine
- kinping.flag包读取命令行配置