文章目录
1. 数组
数组是相同类型 & 长度固定的一组连续数据
1.1 数组的声明和初始化
1)数组的声明
// 1-dim array
var arr [5] int
2)数组的初始化
// 1) 未指定初值 - [0 0 0 0 0]
var arr1 = [5]int{}
// 2) 显示声明初值 - [1 2 3 4 5]
var arr2 = [5]int{1, 2, 3, 4, 5}
// 不设置数组大小 - 会根据元素个数来设置数组大小
var arr3 = [...]int{1, 2, 3, 4, 5}
// 3) 下标赋初值 - [0 0 0 10 0]
var arr4 = [5]int{3: 10}
1.2 访问数组元素
var arr1 = [5]int{}
// 1) 通过索引(位置)来读取
for i := 0; i < len(arr1); i++ {
arr1[i] = i * 10
}
// 2) range遍历数组会有两个返回值 - 数组的索引,第对应的值
for idx, value := range arr1 {
fmt.Printf("index: %d, value: %d\n", idx, value)
}
1.3 多维数组
// multi-dim array
var 3dim [5][3][3]int
初始化
// 倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行
arr1 := [3][4]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
}
// 或者
arr2 := [3][4]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11}}
1.4 数组作为函数参数
Go语言在传递数组时会对其进行拷贝。如果传递的是大数组,会非常占内存,所以一般很少直接传递一个数组。
- 传递数组的指针
- 传递切片
- 定义了长度的数组只能传给限制了相同数组长度的函数 => 值传递,函数中的修改对调用者不可见
- 未定义长度的数组(切片)只能传给不限制数组长度的函数 => 切片包含对底层数组内容的引用,类似指针传递,函数中的修改对调用者可见
package main
import "fmt"
func main() {
arr1 := [5]int{1, 2, 3, 4, 5}
setArray1(arr1)
fmt.Println(arr1) // [1 2 3 4 5]
arr2 := []int{1, 2, 3, 4, 5}
setArray2(arr2)
fmt.Println(arr2) // [5 2 3 4 1]
}
func setArray1(params [5]int) {
params[0], params[len(params)-1] = params[len(params)-1], params[0]
}
func setArray2(params []int) {
params[0], params[len(params)-1] = params[len(params)-1], params[0]
}
1.5 指针数组和数组指针
1)指针数组
- Go语言中数组默认是值传递,所以如果在函数中修改传递过来的数组对原来的数组是没有影响的
- 指针的数组:一个数组里装的都是指针
- 初始化时如果直接
a[i] = &i
,那么指针数组内部存储的全是同一个地址,输出结果也一定是相同的- 数组的参数传递仍是复制的形式(值传递)。但因为数组中每个元素是一个指针,所以函数复制的新数组中的值仍然是这些指针指向的具体地址值,这时改变
a[1]
存储空间地址指向的值,那么原实参指向的值也会变为2。
package main
import "fmt"
func main() {
// 1) 初始化
var arr [5]*int
for i := 0; i < 5; i++ {
temp := i
arr[i] = &temp
}
fmt.Println(arr) // [0xc000014090 0xc000014098 0xc0000140a0 0xc0000140a8 0xc0000140b0]
// 2) 输出
for i := 0; i < 5; i++ {
fmt.Print(*arr[i], " ") // 0 1 2 3 4
}
fmt.Println()
// 3) 在函数中修改传递过来的数组
setArray(arr)
// 4) 输出
for i := 0; i < 5; i++ {
fmt.Print(*arr[i], " ") //0 2 2 3 4
}
}
func setArray(params [5]*int) {
*params[1] = 2
}
2)数组指针(指向数组的指针)
虽然main和setArray中的
arrPtr
是不同的指针,但是它们都指向同一块数组的内存空间,所以无论在main函数还是在setArray函数中对数组的操作都会直接改变数组
package main
import "fmt"
func main() {
var arr [5]int
// 或 aPtr := &a
var arrPtr *[5]int
arrPtr = &arr
fmt.Println(arrPtr) //&[0 0 0 0 0]
setArray(arrPtr)
fmt.Println(arrPtr) //&[0 2 0 0 0]
}
func setArray(params *[5]int) {
params[1] = 2
}
2. 切片
- 切片操作与数组类似,但是它的长度不固定 - 可以追加元素,如果已达到当前切片容量的上限会再自动扩容
- 切片操作"包左不包右"
2.1 切片的初始化
len()
和cap()
获取切片的长度和容量
package main
import "fmt"
func main() {
var slice1 = []int{} //[] 0 0
var slice2 = []int{1, 2, 3, 4, 5} //[1 2 3 4 5] 5 5
var slice3 = make([]int, 5) //[0 0 0 0 0] 5 5
var slice4 = make([]int, 5, 10) //[0 0 0 0 0] 5 10
fmt.Println(slice1, len(slice1), cap(slice1))
fmt.Println(slice2, len(slice2), cap(slice2))
fmt.Println(slice3, len(slice3), cap(slice3))
fmt.Println(slice4, len(slice4), cap(slice4))
}
2.2 切片的基本操作
1)切片扩充
b = append(b, 4)
package main
import "fmt"
func main() {
a := []int{1, 2, 3}
b := a[1:3]
b = append(b, 4)
b = append(b, 5)
b = append(b, 6)
fmt.Println(a) // [1 2 3]
fmt.Println(b) // [2 3 4 5 6]
}
2)切片拼接
a = append(a, b...)
package main
import "fmt"
func main() {
a := []int{1, 2, 3}
b := a[1:3]
fmt.Println(b) // [2 3]
a = append(a, b...)
fmt.Println(a) // [1 2 3 2 3]
}
3)切片的值复制
package main
import "fmt"
func main() {
a := []int{1, 2, 3}
b := make([]int, 3)
copy(b, a) // The value of a is copied to be
fmt.Println(a) // [1 2 3]
fmt.Println(b) // [1 2 3]
}
4)删除元素、插入元素 & 插入切片
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
// 1) 删除处于索引1的元素
fmt.Println(append(a[:1], a[2:]...))
a = []int{1, 2, 3, 4, 5}
// 2) 在索引1的位置插入元素1
// 用append(append(a[:1], 1), a[1:]...) 不正确, 会改变a的取值
fmt.Println(append(a[1:], append(a[:1], 1)...))
a = []int{1, 2, 3, 4, 5}
// 3) 在索引1的位置插入长度为 3的新切片
fmt.Println(append(a[:1], append([]int{0, 0, 0}, a[1:]...)...))
}
2.3 切片 VS 数组
- 对任何一个切片,都有一个底层数组与之对应
- 可将切片看作是一个窗口,透过这个窗口可以看到底层数组的一部分元素
2.1 切片的容量
可以把容量当做成总长度减去左指针走过的元素值
2.2 修改切片
1)切片上再做切片,它们会指向相同的底层数组吗?会
2)修改其中一个切片会影响其他切片的值么? 会
3) 其中一个切片扩容到容量大小之后会更换底层数组,那么之前的其他切片也会指向新的底层数组吗?不会
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
b := a[1:4]
c := b[1:3]
fmt.Println(a, b, c) //[1 2 3 4 5] [2 3 4] [3 4]
c[1] = 9
fmt.Println(a, b, c) //[1 2 3 9 5] [2 3 9] [3 9]
c = append(c, []int{10, 10, 10, 10}...)
fmt.Println(a, b, c) //[1 2 3 9 5] [2 3 9] [3 9 10 10 10 10]
}