文章目录
一、数组
1.数组的一些知识
1.数组:是同一种数据类型的固定长度的序列
2.数组的长度必须是常量,且长度不可修改。例: var a [10]int
3.长度是数组类型的一部分,因此 var a [5]int与var a [10]int是不同类型。
4.数组可以通过下标访问,下标从 0 到 len-1
5.访问越界:如果访问的下标超出数组范围,则触发访问越界,会 panic
6.数组是值类型,因此赋值和传参会复制整个数组。
7.支持"=="和"!="操作符,因为内存总是被初始化过
2.一维数组和多维数组
一维数组:
a := [3]int{1, 2} // 未初始化元素值为 0。
b := [...]int{1, 2, 3, 4} // 通过初始化值确定数组长度。
c := [5]int{2: 100, 4: 200} // 使用索引号初始化元素。
多维数组(这里以二维数组为例):
a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
b := [...][2]int{{1, 1}, {2, 2}, {3, 3}}
3.遍历
一维数组遍历:
for k,v :=range a{
fmt.Println(k, v)
}
多维数组遍历:
for k1, v1 := range a {
for k2, v2 := range v1 {
fmt.Println( k1, k2, v2)
}
}
二、切片(slice)
1.切片的一些知识
slice 并不是数组或数组指针。它通过内部指针和相关属性引用数组片段
1. 切片:切片是数组的一个引用,因此切片是引用类型。但自身是结构体,值拷贝传递。
2. 切片的长度可以改变,因此,切片是一个可变的数组。
3. 切片遍历方式和数组一样,可以用len()求长度。表示可用元素数量,读写操作不能超过该限制。
4. cap可以求出slice最大扩张容量,不能超出数组限制。0 <= len(slice) <= len(array),其中array是slice引用的数组。
5. 切片的定义:var 变量名 []类型,比如 var str []string var arr []int。
6. 如果 slice == nil,那么 len、cap 结果都等于 0。
2.创建切片
// 声明切片
var s1 []int
// :=
s2 :=[]int{}
// make(Type,len,cap)
//使用 make 动态创建slice,避免了数组必须用常量做长度的麻烦。
s3 := make([]int,0)
// 初始化赋值
s4 := []int{1,2,3,4,5}
// 通过数组切片
a :=[5]int{1,2,3,4,5]
// 左包右不包
s5 :=a[1:4] //2,3,4
3.切片的一些基本操作
s[n] 切片 s 中索引为 n 的项
s[:] 从切片 s 中索引 0 到 索引len(s)-1 处所获得的切片
s[m:n] 从切片 s 中索引 m 到索引 n 处所获得的切片
len(s) 切片的长度,总是<=cap(s)
cap(s) 切片的容量,总是>=len(s)
4.用append内置函数操作切片(切片追加)
append :向 slice 尾部添加数据,返回新的 slice 对象。
package main
import (
"fmt"
)
func main() {
var a = []int{1, 2, 3}
fmt.Printf("slice a : %v\n", a)
var b = []int{4, 5, 6}
fmt.Printf("slice b : %v\n", b)
c := append(a, b...)
fmt.Printf("slice c : %v\n", c)
d := append(c, 7)
fmt.Printf("slice d : %v\n", d)
e := append(d, 8, 9, 10)
fmt.Printf("slice e : %v\n", e)
}
输出结果:
slice a : [1 2 3]
slice b : [4 5 6]
slice c : [1 2 3 4 5 6]
slice d : [1 2 3 4 5 6 7]
slice e : [1 2 3 4 5 6 7 8 9 10]
5.扩容策略
可以通过查看$GOROOT/src/runtime/slice.go源码,其中扩容相关代码如下:
GO 1.18版本:
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
const threshold = 256
if old.cap < threshold {
newcap = doublecap
} else {
//检查 0 < newcap 以检测溢出并防止无限循环
for 0 < newcap && newcap < cap {
//从小切片增长 2 倍过渡到大切片增长 1.25 倍
// 平缓newcap增加
newcap += (newcap + 3*threshold) / 4
}
// 如果newcap计算溢出,则设置为cap
if newcap <= 0 {
newcap = cap
}
}
}
6.对切片的操作
1.复制Copy()
Copy():
Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中
copy()函数的使用格式如
copy(destSlice, srcSlice []T) //srcSlice: 数据来源切片 destSlice: 目标切片
func main() {
// copy()复制切片
a := []int{1, 2, 3, 4, 5}
c := make([]int, 5, 5)
copy(c, a) //使用copy()函数将切片a中的元素复制到切片c
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(c) //[1 2 3 4 5]
c[0] = 1000
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(c) //[1000 2 3 4 5]
}
2.删除元素
Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。 代码如下:
func main() {
// 从切片中删除元素
a := []int{30, 31, 32, 33, 34, 35, 36, 37}
// 要删除索引为2的元素
a = append(a[:2], a[3:]...)
fmt.Println(a) //[30 31 33 34 35 36 37]
}
7.切片的本质
切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。举个例子,现在有一个数组a := [8]int{0, 1, 2, 3, 4, 5, 6, 7},切片s1 := a[:5],相应示意图如下。
三、指针
Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值)。
四、Map
map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。
1.Map的定义
map[KeyType]ValueType
KeyType:表示键的类型。
ValueType:表示键对应的值的类型。
2.Map的基本使用
m1:= make(map[string]int, 8)
m1["张三"] = 90
m1["小明"] = 100
或者
m2 := map[string]string{
"username": "GOgo",
"password": "123456",
}
3.判断键值是否存在(ok)
m1:= make(map[string]int)
m1["张三"] = 90
m1["小明"] = 100
if v,ok:=m1["张三"];ok{
fmt.Println(v) //90
}
4.Map遍历
注意: 遍历map时的元素顺序与添加键值对的顺序无关。
for k, v := range m1{
fmt.Println(k, v)
}
5.delete删除键值对
delete(m1, "小明")
总结
本篇文章到这里就要结束了,由于结构体所涉及的知识挺多,所以我决定单独为结构体写一篇文章。
敬请期待😊。