**
详情见我的博客小生博客
**
1.数组
格式化字符串
1.定义数组
var 数组变量名 [元素数量]T
var aa [2]int
2.初始化数组
2.1使用初始化列表
var aa [2]int
var aaa = [2]int{}
var testArray = [3]int{1, 2, 3}
var strArray = [3]string{"akamai", "geetest", "ali"}
fmt.Println(aa)
fmt.Println(testArray)
fmt.Println(strArray) //type of strArray:[3]string
2.2让编译器自行推断数组长度
让编译器根据初始值的个数自行推断数组的长度,
var testArray2 = [...]int{1, 2}
var strArray2 = [...]string{"akamai", "geetest", "ali"}
fmt.Println(testArray2)
fmt.Printf("type of testArray:%T\n", testArray2)
fmt.Println(strArray2)
fmt.Printf("type of strArray:%T\n", strArray2)
2.3使用索引值来初始化数组
a := [...]int{1: 1, 5: 6}
fmt.Println(a)
fmt.Printf("typeof a:%T\n", a)
3.遍历数组
strArray3 := [...]string{"小生", "逆向", ""}
3.1for
for i := 0; i < len(strArray3); i++ {
fmt.Println(strArray3[i])
}
3.2 range
for index, each := range strArray3 {
fmt.Println(index, ",", each)
}
4.多维数组
多维数组只有第一层可以使用...
来让编译器推导数组长度
4.1定义
flatArray := [3][2]int{
{0, 5},
{1, 1},
{2, 2},
}
fmt.Println(flatArray)
fmt.Println(flatArray[0][1])
4.2遍历
for _, v1 := range flatArray {
for _, v2 := range v1 {
fmt.Println(v2)
}
}
//多维数组只有第一层可以使用...来让编译器推导数组长度
5.数组是值类型
//数组是值类型,赋值和传参会复制整个数组。因此改变副本的值,不会改变本身的值。
modifyArray1 := [3]int{1, 2, 3}
copyArray := modifyArray1
fmt.Println("copy array :", copyArray)
modifyArray1 = [3]int{4, 3, 1}
fmt.Println("origin array:", modifyArray1)
fmt.Println("copiedarray:", copyArray)
<注意!!>:
- 数组支持 “==“、”!=” 操作符,因为内存总是被初始化过的。
[n]*T
表示指针数组,*[n]T
表示数组指针 。
7.Slice切片
因为数组长度不可变, 有很多局限性
slice
是一个拥有相同类型元素的可变长度的序列,是基于数组类型做的一层封装,支持自动扩容
切片是一个引用类型,它的内部结构包含地址
、长度
和容量
。切片一般用于快速地操作一块数据集合。
她长的和数组有点像
7.1定义
-
len():
长度 -
cap():
容量
var name []T
T:表示切片中的元素类型
testArray := []int{}
var testArray2 []int
var testArray3 = []string{}
fmt.Println(testArray)
fmt.Println(testArray2)
fmt.Println(testArray3)
fmt.Println(testArray == nil)
fmt.Println(testArray2 == nil)
fmt.Println(testArray3 == nil)
//切片是引用类型,不支持直接比较,只能和nil比较
fmt.Println(cap(testArray))
7.2切片
可以省略切片表达式中的任何索引。省略了low
则默认为0;省略了high
则默认为切片操作数的长度
array[low: high]
`和其他语言一样,取array[low, high) 左包含右不包含
长度 = high - low`
a[2:] // 等同于 a[2:len(a)]
a[:3] // 等同于 a[0:3]
a[:] // 等同于 a[0:len(a)]
//定义一个数组
var arr = [5]int{0, 1, 2, 3, 4}
s := arr[1:3]
fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s)) //s:[1 2] len(s):2 cap(s):4
fmt.Printf("typeof s:%T\n", s) //typeof s:[]int
//为了方便起见,可以省略切片中的任何索引,省略了low则默认为0;省略了high则默认为切片操作数的长度
fmt.Println("-------")
fmt.Println(arr[1:])
fmt.Println("-------")
fmt.Println(arr[:3])
fmt.Println(arr[:])
对切片再执行切片表达式的时候, high上限是切片的容量,而不是切片的长度
ss := arr[0:3]
fmt.Println(len(ss))
fmt.Println(cap(ss))
sss := ss[0:3]
fmt.Println(sss)
7.3完整切片表达式
数组, 指向数组的指针, 切片支持完整切片表达式
arrayp[low, high, max]
他会构造与简单切片表达式array[low, high]
相同类型,相同长度,元素的切片。
- 容量:
max - low
- 长度:
high - low
slic := [5]int{0, 1, 2, 3, 4}
t := slic[1:3:5]
fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
7.4使用make
函数构造切片
make([]int, size, cap)
m := make([]int, 2, 10)
fmt.Println(m) //[0 0]
m = append(m, 10)
m = append(m, 10)
fmt.Println(m)
var nn [1]int
fmt.Println(len(nn), ",,,")
切片本质:对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)
7.5数组判空
使用len(s) == 0
来判断,而不应该使用s == nil
来判断
使用len(s) == 0来判断,而不应该使用s == nil来判断
一个nil
值的长度和内容都是0,但不能说一个长度和内容都为0的切片一定是nil
var s1 []int //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
7.6切片赋值拷贝
slic = [5]int{0, 1, 2, 3, 4}
fmt.Println(slic)
m2 := slic[:]
m3 := m2
fmt.Println("m2:", m2)
fmt.Println("m3:", m3)
m2[0] = 12
fmt.Println("changed")
fmt.Println("m2:", m2)
fmt.Println("m3:", m3)
切片是引用类型, 拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容
7.7append
过var声明的零值切片可以在append()
函数直接使用,无需初始化。
s := []int{} // 没有必要初始化
s = append(s, 1, 2, 3)
var s = make([]int) // 没有必要初始化
s = append(s, 1, 2, 3)
//append添加元素
var n2 []int
//添加一个
n2 = append(n2, 10)
//添加多个
n3 := []int{4, 5}
n2 = append(n2, n3...)
n2 = append(n2, 2, 3, 4)
7.8动态扩容
//切片动态扩容
fmt.Println()
var arr_ac []int
for i := 0; i < 12; i++ {
arr_ac = append(arr_ac, i)
fmt.Printf("arr_ac:%v len:%v cap:%d ptr:%p\n", arr_ac, len(arr_ac), cap(arr_ac), arr_ac)
}
输出:
arr_ac:[0] len:1 cap:1 ptr:0xc0000162f0
arr_ac:[0 1] len:2 cap:2 ptr:0xc000016300
arr_ac:[0 1 2] len:3 cap:4 ptr:0xc00000c360
arr_ac:[0 1 2 3] len:4 cap:4 ptr:0xc00000c360
arr_ac:[0 1 2 3 4] len:5 cap:8 ptr:0xc000012380
arr_ac:[0 1 2 3 4 5] len:6 cap:8 ptr:0xc000012380
arr_ac:[0 1 2 3 4 5 6] len:7 cap:8 ptr:0xc000012380
arr_ac:[0 1 2 3 4 5 6 7] len:8 cap:8 ptr:0xc000012380
arr_ac:[0 1 2 3 4 5 6 7 8] len:9 cap:16 ptr:0xc00001e200
arr_ac:[0 1 2 3 4 5 6 7 8 9 10] len:11 cap:16 ptr:0xc00001e200
arr_ac:[0 1 2 3 4 5 6 7 8 9 10 11] len:12 cap:16 ptr:0xc00001e200
- 切片numSlice的容量按照1,2,4,8,16这样的规则自动进行扩容,每次扩容后都是扩容前的2倍。
-
append()
函数将元素追加到切片的最后并返回该切片。
7.9copy
a := []int{1, 2, 3, 4, 5}
b := a
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(b) //[1 2 3 4 5]
b[0] = 100
fmt.Println(a) //[100 2 3 4 5]
fmt.Println(b) //[100 2 3 4 5]
copy(destination, source)
7.10删除切片中元素
Go语言中并没有删除切片元素的专用方法,可以使用切片本身的特性来删除元素。
aaa := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1}
aaaa := append(aaa[:3], aaa[4:]...)
fmt.Println(aaaa)
7.11试题
func main() {
var a = make([]string, 5, 10)
for i := 0; i < 10; i++ {
a = append(a, fmt.Sprintf("%v", i))
}
fmt.Println(a)
}
写出输出结果:
[ 0 1 2 3 4 5 6 7 8 9]
前面有五个空字符串!!!!!
7.12试题
使用内置的sort包对数组var a = [...]int{3, 7, 8, 9, 1}进行排序
:
var ar = [...]int{3, 7, 8, 9, 1}
after := ar[:]
sort.Sort(sort.IntSlice(after))
fmt.Println(after)
`补充:`
d := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Sort(sort.IntSlice(d))
fmt.Println(d)
// Output:[1 2 3 4 5 6]
a := []float64{5.5, 2.2, 6.6, 3.3, 1.1, 4.4}
sort.Sort(sort.Float64Slice(a))
fmt.Println(a)
// Output:[1.1 2.2 3.3 4.4 5.5 6.6]
s := []string{"PHP", "golang", "python", "C", "Objective-C"}
sort.Sort(sort.StringSlice(s))
fmt.Println(s)
// Output:[C Objective-C PHP golang python]