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是引用类型。

  

原文地址:https://www.cnblogs.com/-beyond/p/8110634.html