1、数组
1.1 数组类型
var 数组名 [数组大小]数据类型
package main import "fmt" func main(){ //1、定义一个数组 var arr1 [5]int arr1[0] = 100 arr1[1] = 200 fmt.Println(arr1) //[100 200 0 0 0] }
1.2 数组的初始化方式
package main import "fmt" func main(){ //第一种: var arr1 [3]int = [3]int{3,6,9} //指定类型 fmt.Println(arr1) //第二种: var arr2 = [3]int{1,4,7} //自动类型推导 fmt.Println(arr2) //第三种: var arr3 = [...]int{4,5,6,7} //自动类型推导 fmt.Println(arr3) //第四种: var arr4 = [...]int{2:66,0:33,1:99,3:88} //指定下标初始化+自动类型推导 fmt.Println(arr4) }
注意:
- 定义数组时,声明的长度不同,即使元素的数据类型相同,但整体的数组类型也是不同的,即长度也是属于类型的一部分
- Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝,即形参不影响实参
- 如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)
package main import "fmt" func f(arr *[]int){ for i := 0; i < len(*arr); i++ { (*arr)[i] += 10 } } func main(){ var arr []int = []int{1,2,3,4,5,6,7,8,9,0} f(&arr) fmt.Println(arr) //[11 12 13 14 15 16 17 18 19 10] }
1.3 数组内存
package main import "fmt" func main(){ //声明数组: var arr [3]int16 //获取数组的长度: fmt.Println(len(arr)) //打印数组: fmt.Println(arr)//[0 0 0] //证明arr中存储的是地址值: fmt.Printf("arr的地址为:%p",&arr) //第一个空间的地址: fmt.Printf("arr的地址为:%p",&arr[0]) //第二个空间的地址: fmt.Printf("arr的地址为:%p",&arr[1]) //第三个空间的地址: fmt.Printf("arr的地址为:%p",&arr[2]) }
注意:数组每个空间占用的字节数取决于数组类型
数组优点:可以通过[]下标进行线性访问
1.4 数组遍历
1、使用普通for循环
2、使用for-range循环 (key - value)
package main import "fmt" func main(){ var arr1 = [...]int{1,2,3,4,5,6,7,8,9,10} //普通for循环遍历 for i := 0; i < len(arr1); i++{ arr1[i] += 10 fmt.Println(arr1[i]) //11 12 13 14 15 16 17 18 19 20 } fmt.Println("") //for-range遍历 for k,v := range arr1{ v += 10 //v只是一个副本,对v的修改不会影响arr1的元素 fmt.Println(arr1[k]) //11 12 13 14 15 16 17 18 19 20 } fmt.Println("") }
注意:使用for-range时,接收的value变量只是一个副本,副本改变不影响原来arr1数组的元素
1.5 二维数组/多维数组
定义:
package main import "fmt" func main(){ //定义二维数组 var arr [3][4]int = [3][4]int{{1,2,3,4},{5,6,7,8},{9,10,11,12}} //遍历二维数组 for i := 0; i < len(arr); i++ { for j := 0; j < len(arr[i]); j++ { fmt.Printf("%d ",arr[i][j]) //1 2 3 4 5 6 7 8 9 10 11 12 } } fmt.Println("") //定义多维数组 var arr2 [3][2][2][2]int = [3][2][2][2]int{{{{1,2},{3,4}},{{5,6},{7,8}}},{{{9,10},{11,12}},{{13,14},{15,16}}},{{{17,18},{19,20}},{{21,22},{23,24}}}} //遍历多维数组 for i := 0; i < len(arr2); i++ { for j := 0; j < len(arr2[i]); j++ { for k := 0; k < len(arr2[i][j]); k++ { for l := 0; l < len(arr2[i][j][k]); l++ { fmt.Printf("%d ",arr2[i][j][k][l]) //1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 } } } } }
package main import "fmt" func main(){ //定义二维数组 var arr [3][4]int = [3][4]int{{1,2,3,4},{5,6,7,8},{9,10,11,12}} //遍历二维数组 for k1,v1 := range arr{ for k2,v2 := range v1{ fmt.Printf("arr[%v][%v] = %v\n",k1,k2,v2) } } //定义多维数组 var arr2 [2][2][2][2]int = [2][2][2][2]int{{{{1,2},{3,4}},{{5,6},{7,8}}},{{{9,10},{11,12}},{{13,14},{15,16}}}} //遍历多维数组 for k1,v1 := range arr2{ for k2,v2 := range v1{ for k3,v3 := range v2{ fmt.Printf("arr2[%v][%v][%v] = %v\n",k1,k2,k3,v3) } } } }
2、切片
2.1 切片
- 切片(slice)是golang中一种特有的数据类型
- 数组有特定的用处,但数组长度固定不可变,所以在 Go 语言的代码里并不是特别常见。相对的切片却是随处可见的,切片是一种建立在数组类型之上的抽象,它构建在数组之上并且提供更强大的能力和便捷。
- 切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口。
切片的语法:
var 切片名 []类型 = 数组的一个片段引用
2.2 切片的内存分析
切片有3个字段的数据:
- 一个是指向底层数组的指针
- 一个是切片的长度
- 一个是切片的容量
2.3 切片的定义
方式1:定义一个切片,然后让切片去引用一个已经创建好的数组
方式2:通过make内置函数来创建切片。基本语法: var切片名[type = make([], len,[cap])
(make底层创建一个数组,对外不可见,所以不可以直接操作这个数组,要通过slice去间接的访问各个元素,不可以直接对数组进行维护/操作)
方式3:定一个切片,直接就指定具体数组,使用原理类似make的方式。
注意:
切片定义后不可以直接使用,需要让其引用到一个数组,或者make一个空间供切片来使用
不能越界package main import "fmt" func main(){ //方式一:定义一个切片,然后让切片去引用一个已经创建好的数组。 var arr [5]int = [5]int{1,2,3,4,5} var slice []int slice = arr[1:3] fmt.Println(slice) //方式二:通过make内置函数来创建切片。基本语法: var切片名[type = make([], len,[cap]) // make函数的三个参数:1、切片类型;2、切片的长度;3、切片的容量。 slice1 := make([]int, 5, 10) fmt.Println(slice1) fmt.Println(slice1[6]) //方式三:定义一个切片,直接就指定具体数组。使用原理类似make的方式。 slice2 := []int{1,2,3,4,5} fmt.Println(slice2) }
简写方式:
var slice = arr[0:end] ----> var slice = arr[:end] //从起始到指定位置
var slice = arr[start:len(arr)] ----> var slice = arr[start:] //从指定位置到末尾
var slice = arr[0:len(arr)] ----> var slice = arr[:] //从起始位置到末尾位置
可以对切片继续切片:
package main import "fmt" func main(){ var arr [5]int = [5]int{0,1,2,3,4} var slice1 []int = arr[:3] var slice2 []int = slice1[1:2] slice2[0] = 100 fmt.Println(arr) //[0 100 2 3 4] fmt.Println(slice1) //[0 100 2] fmt.Println(slice2) //[100] }
2.4 切片的遍历
package main
import "fmt"
func main(){
//定义一个切片
slice := []int{1,2,3,4,5}
//方式一:for
for i := 0; i < len(slice); i++ {
fmt.Println(slice[i]) //1 2 3 4 5
}
//方式二:for-range
for _,v := range slice{
fmt.Println(v) //1 2 3 4 5
}
}
2.5 切片的动态增长
package main
import "fmt"
func main(){
var arr [5]int = [5]int{0,1,2,3,4}
slice := arr[2:]
fmt.Println(slice) //[2 3 4 0 0]
slice = append(slice, 1,2,3,4)
fmt.Println(slice) //[2 3 4 1 2 3 4]
slice1 := append(slice,100,200,300)
fmt.Println(slice1) //[2 3 4 1 2 3 4 100 200 300]
}
package main
import "fmt"
func main(){
//定义数组:
var intarr [6]int = [6]int{1,4,7,3,6,9}
//定义切片:
var slice []int = intarr[1:4] //4,7,3
fmt.Println(len(slice))
slice2 := append(slice,88,50)
fmt.Println(slice2) //[4 7 3 88 50]
fmt.Println(slice)
//底层原理:
//1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组:
//2.创建一个新数组,将老数组中的4,7,3复制到新数组中,在新数组中追加88,50
//3.slice2 底层数组的指向 指向的是新数组
//4.往往我们在使用追加的时候其实想要做的效果给slice追加:
slice = append(slice,88,50)
fmt.Println(slice)
//5.底层的新数组 不能直接维护,需要通过切片间接维护操作。
}
可以通过append函数将切片追加给切片:
2.6 切片的拷贝
使用函数:copy(目标切片,源切片)
package main
import "fmt"
func main(){
//定义切片:
var a []int = []int{1,4,7,3,6,9}
var b []int = make([]int,10)
//拷贝:
copy(b,a) //将a中对应数组中元素内容复制到b中对应的数组中
fmt.Println(b) //[1 4 7 3 6 9 0 0 0 0]
}
3、映射
映射(map), Go
语言中内置的一种类型,它将键值对相关联,我们可以通过键 key
来获取对应的值value
。
3.1 语法
语法:var 变量名 map[keytype]valuetype
注意:key、value的类型:bool、数字、string、指针、channel 、还可以是只包含前面几个类型的接口、结构体、数组,key不可以是slice、map、function
特点:
- map集合在使用前一定要make
- map的key-value是无序的
- key是不可以重复的,如果遇到重复,后一个value会替换前一个value
- value可以重复的
3.2 创建方式
package main
import "fmt"
func main(){
//方式1:
//定义map变量:
var a map[int]string
//只声明map内存是没有分配空间
//必须通过make函数进行初始化,才会分配空间:
a = make(map[int]string,10) //map可以存放10个键值对
//将键值对存入map中:
a[20095452] = "张三"
a[20095387] = "李四"
//输出集合
fmt.Println(a)
//方式2:
b := make(map[int]string)
b[20095452] = "张三"
b[20095387] = "李四"
fmt.Println(b)
//方式3:
c := map[int]string{
20095452 : "张三",
20098765 : "李四",
}
c[20095387] = "王五"
fmt.Println(c)
}
3.3 map的操作
增加和更新操作:
map["key"]= value , 如果key还没有,就是增加,如果key存在就是修改。
删除操作:
delete(map,"key") , delete是一个内置函数,如果key存在,就删除该key-value,如果key不存在,不操作,但是也不会报错
清空操作:
如果我们要删除map的所有key ,没有一个专门的方法一次删除,可以遍历一下key,逐个删除
或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收
查找操作:
value ,bool = map[key]
value为返回的value,bool为是否返回 ,要么true 要么false
package main import "fmt" func main(){ //定义map b := make(map[int]string) //增加: b[20095452] = "张三" b[20095387] = "李四" //修改: b[20095452] = "王五" //删除: delete(b,20095387) delete(b,20089546) fmt.Println(b) //查找: value,flag := b[200] fmt.Println(value) fmt.Println(flag) }
获取长度:len函数
遍历:for-range
package main import "fmt" func main(){ //定义map变量 //make5个键值对 var mp map[string]string = make(map[string]string,5) mp["string"] = "字符串" mp["int"] = "整型" mp["float"] = "浮点型" mp["bool"] = "布尔型" mp["array"] = "数组" //遍历map for k,v := range mp{ fmt.Printf("key = %v,value = %v\n",k,v) } }