Golang 数组、切片、映射

时间:2023-04-10 14:57:32

定义数组

var arr1 [5]int   //整型类型
fmt.Println(arr1) //[0 0 0 0 0]
//赋值
arr1 = [5]int{1, 2, 3, 4, 5}
fmt.Println(arr1) //[1 2 3 4 5] var arr2 [6]*int //整型指针数组
fmt.Println(arr2) //[<nil> <nil> <nil> <nil> <nil> <nil>] var arr3 [2][3]int //二维数组
fmt.Println(arr3) //[[0 0 0] [0 0 0]] // 使用简短的格式
arr4 := [5]int{2, 4, 6, 8, 10}
fmt.Println(arr4) //[2 4 6 8 10] //其他方式,如果长度的位置是... 表示数组长度是根据后面的数据元素个数来计算
arr5 := [...]int{2, 3, 4, 5, 6, 7}
fmt.Println(arr5, len(arr5)) //[2 3 4 5 6 7] 6 // 指定数组的索引来赋值
arr6 := [...]int{5: 10, 7: 23}
//将数组下标为5的元素赋值为10,将数组下标为7的元素赋值为23
//数组长度为8
fmt.Println(arr6, len(arr6)) //[0 0 0 0 0 10 0 23] 8 arr7 := [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Println(arr7) //[[1 2 3] [4 5 6]]

  

数组访问与数组长度

arr1 := [5]int{2, 4, 6, 8, 10}
fmt.Println(arr1) // [2 4 6 8 10]
fmt.Println("length:", len(arr1)) //length: 5
// arr1[5] = 100 //出错,数组越界
arr1[0] = 99
fmt.Println(arr1) //[99 4 6 8 10] arr2 := [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Println(len(arr2)) //2
fmt.Println(len(arr2[0])) //3
fmt.Println(arr2[1][1]) //5

  

数组遍历

arr1 := [5]int{2, 4, 6, 8, 10}
for i := 0; i < len(arr1); i++ {
fmt.Println(arr1[i]) //2 4 6 8 10
}
for i, v := range arr1 {
fmt.Print(i, "=>", v) // 0=>2,1=>4,2=>6,3=>8,4=>10
}
// 不需要索引的时候,可以将用_代替i
for _, v := range arr1 {
fmt.Println(v) //2,4,6,8,10
}

  

数组作为函数参数

  数组作为函数作为参数时,如果是给形参传递数组名,那么就是传值操作,传递的是数组的副本,修改副本的内容,并不会影响实参。

  要想在函数中对数组的修改作用到实参,可以用数组指针,即->使用指针的形式,将数组的地址传递给函数,并且函数定义时,接收一个指针类型的参数,那么就可以对数组内部进行修改,但是不能修修改数组长度。

package main

import "fmt"

func Double(arr [5]int) [5]int {
for i := 0; i < 5; i++ {
arr[i] *= 2
}
return arr
} //接收的指针类型,即数组的地址
//注意这里的形参要写成 arr *[5]int 不要写成arr [5]*int
//arr [5]*int表示的是有五个元素的数组,每个元素是一个指针,即5个指针
//arr *[5]int表示的是一个指针,这一个指针指向一个拥有5个元素的数组,每个元素时一个int型变量
func Triple(arr *[5]int) {
for i := 0; i < 5; i++ {
arr[i] *= 3
}
}
func main() {
var arr2 [6]*int //整型指针数组
fmt.Println(arr2) //[<nil> <nil> <nil> <nil> <nil> <nil>]
arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr) //[1 2 3 4 5] arr1 := Double(arr)
fmt.Println(arr1) //[2 4 6 8 10]
fmt.Println(arr) //[1 2 3 4 5] Triple(&arr)
fmt.Println(arr) //[3 6 9 12 15]
}

  

数组类型、数组比较

  数组的长度一旦确定,就不能再改变。如果要改变,只能转换为slice,但是用了slice之后,改变的是slice的长度,但是数组长度始终不变。

  数组长度不同,那么数组就不是同一个类型,不能相互赋值-->参数传递。

  相同类型的数组可以进行比较,这里的类型不只是数组元素的类型,也包括数组的长度都要相同,才能进行比较。

package main
import "fmt"
func Double(arr [5]int) [5]int {
for i := 0; i < 5; i++ {
arr[i] *= 2
}
return arr
} func main() {
arr1 := [5]int{1, 2, 3, 4, 5}
Double(arr1) //正确 形参和实参都是[5]int类型,注意[5]int是一个类型 arr2 := [6]int{1, 2, 3, 4, 5, 6}
Double(arr2) //错误,不能将类型为[6]int的实参,赋值给类型为[5]int的形参
//[5]int和[6]int是两个不同的类型
}

  

  

创建切片

var slice []int
//定义一个空切片,注意上面[]中没有指定长度,如果指定长度,就代表是数组了
fmt.Println(slice) //[] slice1 := []int{1, 2, 3, 4, 5}
//创建一个长度和容量为5的切片
fmt.Println(slice1) //[1 2 3 4 5]
fmt.Println(len(slice1), cap(slice1)) //5 5 slice2 := []int{5: 10}
//创建一个长度和容量为6的切片
fmt.Println(slice2) //[0 0 0 0 0 10]
fmt.Println(len(slice2), cap(slice2)) //6 6 //使用make创建切边
//make(type,len,cap),未指定cap是,cap和len相等
slice3 := make([]int, 5, 10)
fmt.Println(slice3, len(slice3), cap(slice3)) //[0 0 0 0 0] 5 10
slice4 := make([]int, 6)
fmt.Println(slice4, len(slice4), cap(slice4)) //[0 0 0 0 0 0] 6 6 // 利用数组创建切片
//[strat:end]左闭右开,start省略时,默认为0;end省略时默认为数组或者切片长度
arr := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice5 := arr[3:]
fmt.Println(slice5) //[3 4 5 6 7 8 9] slice6 := arr[:7]
fmt.Println(slice6) //[0 1 2 3 4 5 6] slice7 := arr[4:8]
fmt.Println(slice7) //[4 5 6 7] slice8 := arr[:]
fmt.Println(slice8) //[0 1 2 3 4 5 6 7 8 9]

  通过len函数求的切片长度,判断是否为空。

append函数

  使用append函数后,返回的是一个slice类型,不是数组类型

slice := []int{1, 2, 3, 4, 5}
fmt.Println(slice) //[1 2 3 4 5] //追加元素
slice = append(slice, 6)
fmt.Println(slice) //[1 2 3 4 5 6] //追加切片
s1 := []int{99, 100}
//注意下面的...表示解构,即,将切片的内容展开后填充到该位置
slice = append(slice, s1...)
fmt.Println(slice)

  不能对数组调用append函数,即,append函数的第一个参数必须是slice。

copy函数

  copy(destination,resource),复制之后,dest的长度并不会改变,即使复制给他的切片长度远大于它。

//长的slice复制到短的slice
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{10, 20, 30, 40}
copy(s2, s1)
fmt.Println(s2) //[1 2 3 4] //短的slice复制到长的slice
s3 := []int{2, 3, 4}
s4 := []int{9, 8, 7, 6, 5}
copy(s4, s3)
fmt.Println(s4) //[2 3 4 6 5] //相同长度的slice进行复制
s5 := []int{1, 2, 3}
s6 := []int{4, 5, 6}
copy(s6, s5)
fmt.Println(s6) //[1 2 3]

  不能使用copy进行数组的复制操作,即,copy的两个参数都必须是slice。

slice作为函数参数

  将数组传递给函数之后,在函数中操作的是数组的副本。虽然可以使用数组指针形式传递,但是更通用的是使用slice,使用slice之后,可以通过在函数中修改slice,来达到修改数组的目的。

package main

import "fmt"

//参数是数组类型
func Double(arr [5]int) {
for i := 0; i < 5; i++ {
arr[i] *= 2
}
} //类型是slice类型
func Triple(slice []int) {
for i := 0; i < len(slice); i++ {
slice[i] *= 3
}
}
func main() {
arr := [5]int{1, 2, 3, 4, 5}
Double(arr)
fmt.Println(arr) //[1 2 3 4 5] //数组转换为切片
slice := arr[:]
Triple(slice)
fmt.Println(arr) //[3 6 9 12 15]
}

  

创建map

//定义空的映射,默认值为nil
var m1 map[int]string
fmt.Println(m1) //map[]
//再进行初始化
m1 = map[int]string{
1: "hello",
8: "world", //注意这种写法,末尾的逗号不可省
}
fmt.Println(m1) //map[1:hello 8:world] //使用make创建映射,注意此时最多只用两个参数,
//一个是map的映射类型,一个map的容量,容量可以省略
//但是没有len这一个参数,即不能指定长度这一项
m2 := make(map[int]string, 100)
fmt.Println(m2, len(m2)) m3 := make(map[string][]string)
m3["server"] = []string{"apache", "nginx"}
m3["language"] = []string{"php", "golang", "python"}
fmt.Println(m3) //map[server:[apache nginx] language:[php golang python]] //创建映射,同时初始化,此时不需要使用make
m4 := map[int]string{1: "demo", 2: "test"}
fmt.Println(m4) //map[1:demo 2:test]

  

删除map元素

//字符串映射到string类型的切片
m1 := map[string][]string{
"server": []string{"apache", "nginx"},
"language": []string{"php", "python", "golang"},
}
fmt.Println(m1) //map[server:[apache nginx] language:[php python golang]] //删除没有的key,不报错
delete(m1, "client")
fmt.Println(m1) //map[server:[apache nginx] language:[php python golang]] delete(m1, "server")
fmt.Println(m1) //map[language:[php python golang]]

  

查找map元素

//字符串映射到string类型的切片
m1 := map[string][]string{
"server": []string{"apache", "nginx"},
"language": []string{"php", "python", "golang"},
}
fmt.Println(m1) //map[server:[apache nginx] language:[php python golang]] //访问一个不存在的元素,不会报错,返回类型零值
fmt.Println(m1["client"]) //[] v, exists := m1["client"]
fmt.Println(v, exists) //[] false v, exists = m1["server"]
fmt.Println(v, exists) //[apache nginx] true

  

遍历map

//字符串映射到string类型的切片
m1 := map[string][]string{
"server": []string{"apache", "nginx"},
"language": []string{"php", "python", "golang"},
}
for key, value := range m1 {
fmt.Println(key, "=>", value)
}
//server => [apache nginx]
//language => [php python golang]

  映射是无序的,所以遍历多次的结果,元素的顺序不一定完全相同

map注意事项

  1、map之间不能进行比较,但是可以和nil进行比较

  2、不能对map取地址,因为map本就是引用类型

var m0 map[int]string
fmt.Println(m0 == nil) //true var m1 map[int]string
fmt.Println(m0 == m1) //不能进行比较,会报错 m2 := map[int]string{1: "one", 2: "two"}
fmt.Println(m2 == nil) //false

  

map作为函数参数

package main

import "fmt"

//接受一个map
func Show(m map[int]string) {
m[1] = "three"
m[3] = "four"
}
func main() {
m1 := map[int]string{
1: "one",
2: "two",
}
fmt.Println(m1) //map[1:one 2:two] Show(m1)
fmt.Println(m1) //map[3:four 1:three 2:two]
}

  将map作为函数的参数,在函数中修改map,会直接影响到实参,因为map是引用类型。