Golang 数组、切片、映射
定义数组
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是引用类型。