Go4-数组+切片+map
1.数组的定义、赋值、访问和遍历
// 1 数组用来存放多个同一类型的数据,在Go中数组是值类型。
// 2 数组的定义、赋值和遍历。
// 定义数字。
var arrs [2]int
// 给数组元素赋值。
arrs[0] = 0
arrs[1] = 2
// 0 2
for i := 0; i < len(arrs); i++ {
fmt.Println(arrs[i])
}
// 0 = 2 ; 1 = 2
for index, value := range arrs {
fmt.Println(index, "=", value)
}
// 3 通过地址访问数据中的元素。
var a2 [2]int
a2[0] = 1
a2[1] = 2
// // 3.1 数组的地址就是数组第一个元素的地址。
// 数组的地址0xc00000a0d0,数组第一个元素的地址0xc00000a0d0
fmt.Printf("数组的地址%p,数组第一个元素的地址%p\n", &a2, &a2[0])
// 3.2 通过数组地址的指向获取数组的值。
// 0xc00000a0d8 2
fmt.Println(&a2[1], *&a2[1])
// 4 四种初始化数组的方式。
// 4.1 初始化数组的方式一。
var a3 [3]int = [3]int{1, 2, 3}
fmt.Println(a3) // [1 2 3]
// 4.2 初始化数组的方式二。
var a4 = [3]int{1, 2, 3}
fmt.Println(a4) // [1 2 3]
// 4.3 初始化数组的方式三。
// 这里的[...]是规定的写法。
var a5 = [...]int{1, 3, 5}
fmt.Println(a5) // [1 3 5]
// 4.4 初始化数组的方式四,按照索引初始化数据。
var a6 = [...]int{1: 100, 0: 10, 2: 1000}
fmt.Println(a6) // [10 100 1000]
// 4.5 初始化数组的方式五。
a7 := [...]string{1:"3", 0:"1", 2:"5"}
fmt.Println(a7)
// 5 数组for...range遍历。
// 5.1 for...range遍历不忽略索引。
a8 := [...]int{1, 10}
// 0 1; 1 10;
for index, value := range a8 {
fmt.Println(index, value, ";")
}
// 5.2 for...range遍历使用_忽略索引。
// 1 10
for _, value := range a8 {
fmt.Println(value)
}
// 5.3 for...range变量时,如果只有一个返回值,则返回的是索引。
// 0 1
for index := range a8 {
fmt.Println(index)
}
2.数组的注意事项和使用细节
func main() {
// 1 数组一旦定义了长度就不能改变了;
// 数组一旦定义了存储的数据类型就只能存储是定义的类型。
// 2 数组定义之后没有赋值就是默认值。
//数值(整数和浮点型)默认值为0,字符串默认值为""空串, bool默认值为false。
var a1 [3]int
fmt.Println(a1) // [0 0 0]
// 3 数组的下标必须在指定范围之内,否则报错。
// 报错:invalid argument: array index 3 out of bounds [0:3]
// a1[3] = 1
// 4 Go中数组属于值类型,默认情况下是指传递,会进行值拷贝。
// 函数之间数组传递之后的修改不会影响原数组的值。
a2 := [...]int{1, 3, 5}
fmt.Println(1, a2) // 1 [1 3 5]
test01(a2)
fmt.Println(3, a2) // 3 [1 3 5]
// 5 数组默认是值传递,如果在函数传递时想修改数组的值,可以使用指针进行引用传递。
a3 := [...]int{2, 4, 6}
fmt.Println(1, a3) // 1 [2 4 6]
test02(&a3)
fmt.Println(3, a3) // 3 [2 100 10]
// 6 使用byte数组保存A-Z,然后输出打印。
var a4 [26]byte
for i := 0; i < 26; i++ {
a4[i] = 'A' + byte(i)
}
// [A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
fmt.Printf("%c", a4)
}
func test02(a *[3]int) {
// 两种通过指针修改数组值的方式,推荐使用第二种,容易理解。
// 不推荐使用这种方式修改数组的值。
*(&(a[2])) = 10
// *a取数组a的首地址,(*a)[1]然后偏移1位。
(*a)[1] = 100
fmt.Println(a) // &[2 100 10]
}
func test01(a [3]int) {
a[0] = 10
fmt.Println(2, a) // 2 [10 3 5]
}
3.切片的创建和遍历
// 1 切片相当于动态数组,在数组的长度不确定时就可以使用切片来定义数组。
// 2 切片是数组的一个引用,因此切片是引用类型。
// 3 切片的定义语法。var 切片名 []类型
var a1 [5]int = [5]int{1, 3, 5, 7, 8}
var a2 []int = a1[1 : 3]
// 切片 [3 5]
fmt.Println("切片", a2)
// 切片元素的个数 2
fmt.Println("切片元素的个数", len(a2))
// 切片的容量 4
fmt.Println("切片的容量", cap(a2))
// 4 从底层上来讲切片就是一个结构体。
/*
type slice struct {
ptr *[2]int // 保存数据的首地址。
len int // 保存数组中元素的个数。
cap int // 保存切片的容量。
}
*/
// 5 切片的三种创建使用。
// 5.1 切片的创建方式一,通过数组来创建切片。
var a3 [5]int = [5]int{1, 10, 100, 1000, 10000}
// 取数组的索引1和索引2处的值,1:3,表示1-3,但是不包含3。
var a4 []int = a3[1:3]
fmt.Println(a4) // [10 100]
// 5.2 切片的创建方式二,使用make来创建切片。
// 语法 var 切片名 []type = make([]type, len, [cap])
// type是要创建的切片的类型;len切片的大小;cap是切片的容量,可选,如果设置了cap,则需要cap大于等于len。
var a5 []float64 = make([]float64, 5, 10)
fmt.Println(len(a5), cap(a5)) // 5 10
var a6 []float64 = make([]float64, 5)
fmt.Println(len(a6), cap(a6)) // 5 5
// 5.3 切片的创建方式三,直接初始化切片。
var a7 []int64 = []int64{1, 2, 3, 5, 7}
fmt.Println(a7) // [1 2 3 5 7]
fmt.Println(len(a7), cap(a7)) // 5 5
// 5.4 引用数组创建切片和make创建切片的区别。
// 引用数组创建切片,数组是存在的,这个数组对程序员来说是可见的。
// 通过make创建切片,make会先创建一个数组,这个数组由切片维护,数组对程序员来说是不可见的。
// 6 切片的两种遍历方式。
a8 := []int{1, 2, 3}
// 常规for循环遍历。
// 1 2 3
for i := 0; i < len(a8); i++ {
fmt.Println(a8[i])
}
// for...range遍历切片。
// 0 1 ; 1 2 ; 2 3 ;
for index, value := range a8 {
fmt.Println(index, value, ";")
}
4.切片的使用细节和常用函数
func main() {
// 1 切片在初始化时,不能超过数组的长度,范围在0-len(arr)之间,
// 但是切片长度可以动态增长。
var a1 [3]int = [3]int{1, 2, 3}
var a2 []int = a1[0 : len(a1)]
fmt.Println(a2) // [1 2 3]
// 2 创建切片的简写方式。
// var a3 []int = a1[0, end]的简写。
var a3 []int = a1[:1]
fmt.Println(a3) // [1]
// var a4 []int = a1[start: len(a1)]的简写。
var a4 []int = a1[1:]
fmt.Println(a4) // [2 3]
// var a5 []int = a1[0 : len(a1)]的简写。
var a5 []int = a1[:]
fmt.Println(a5) // [1 2 3]
// 3 对切片的切割。
a6 := [...]int{1, 2, 3, 4, 5}
a7 := a6[:]
a8 := a7[1:2]
fmt.Println(a7, a8) // [1 2 3 4 5] [2]
// 4 append()内置函数,对切片进行动态追加。
var a9 []int = []int{1}
fmt.Println(a9) // 1
a9 = append(a9, 10, 20)
fmt.Println(a9) // [1 10 20]
a10 := []int{-1, -2}
// append()如果追加的是一个切片,则需要将切片解构为元素。
// a10...,将切片解构为数组。
a9 = append(a9, a10...)
// [1 10 20 -1 -2]
fmt.Println(a9)
// 5 copy()内置函数,进行切片数据的拷贝。
a11 := []int{1, 2}
var a12 []int = make([]int, 5)
fmt.Println(a12) //
copy(a12, a11)
fmt.Println(a12) // [1 2 0 0 0]
// 将len()大的切片拷贝给len()小的切片。
var a13 = make([]int, 1)
copy(a13, a11)
fmt.Println(a13) // [1]
// 6 切片是引用类型,在传递时遵循引用类型的传递机制。
a14 := [...]int{1, 10, 100}
a15 := a14[:]
a16 := a15
a16[0] = -1
fmt.Println(a16) // [-1 10 100]
fmt.Println(a14) // [-1 10 100]
fmt.Println(a15) // [-1 10 100]
a17 := []int{1, 2}
fmt.Println(a17) // [1 2]
test01(a17)
fmt.Println(a17) // [-10 2]
}
func test01(a []int) {
a[0] = -10
}
5.string和slice
// 1 string底层是一个byte数组,因此string也可以进行切片的操作。
a1 := "hello张三"
a2 := a1[1:5]
fmt.Println(a2) // ello
// 使用数组切片时需要注意汉字占用了三个字节。
a3 := a1[1:6]
fmt.Println(a3) // ello�
a4 := a1[1:8]
fmt.Println(a4) // ello张
// 2 string类型是不可变的,所以不能通过a[0] = 'a'修改字符串。
a5 := "hello"
fmt.Println(a5) // hello
// 报错:cannot assign to a5[0] (value of type byte)
// a5[0] = "n"
// 3 如果需要修改字符串,则可以将字符串转[]byte或者[]rune,修改之后在转换为字符串。
// 3.1 将字符串转换为[]byte,修改在转换为字符串。
// 转换为[]byte不能用于中文的修改, 因为[]byte按照字节处理,一个中文占用三个字节。
// 对于[]byte不能处理中文修改的问题,可以将字符串转换为[]rune来处理。
a6 := "hello"
var a7 []byte = []byte(a6)
a7[0] = 'a'
a6 = string(a7)
fmt.Println(a6) // aello
// 3.2 将字符串转换为[]rune来解决修改中文乱码问题。
a8 := "h张三"
a9 := []rune(a8)
a9[1] = '李'
a9[2] = '1'
a8 = string(a9)
fmt.Println(a8) // h李1
6.二维数组
// 1 二维数组的使用方式一,先声明定义,在赋值。
var a1 [2][3]int
a1[0][0] = 1
a1[0][1] = 2
a1[0][2] = 3
a1[1][0] = 4
a1[1][1] = 5
a1[1][2] = 6
fmt.Println(a1) // [[1 2 3] [4 5 6]]
// 2 二维数组的使用方式二,直接初始化。
var a2 [2][3]int = [2][3]int{{1, 10, 100}, {1, 2, 3}}
fmt.Println(a2) // [[1 10 100] [1 2 3]]
// 3 二维数组声明定义的方式三。
var a3 = [...][2]int{{2, 4}, {1, 3}}
fmt.Println(a3) // [[2 4] [1 3]]
// 4 二维数组的遍历。
// 4.1 二维数组传统的方式遍历。
var a4 = [...][2]int{{2, 4}, {1, 3}}
/*
2 4
1 3
*/
for i := 0; i < len(a4); i++ {
for j := 0; j < len(a4[i]); j++ {
fmt.Printf("%d\t", a4[i][j])
}
fmt.Println()
}
// 4.2 for...range遍历二维数组。
/*
2 4
1 3
*/
for _, v1 := range a4 {
for _, v2 := range v1 {
fmt.Printf("%d\t", v2)
}
fmt.Println()
}
7.map初始化和赋值
// 1 map的key可以是bool、int、float、string、指针、channel、接口、结构体和数组;
// 但是map的key不能是slice、map和function,因为这三种类型无法进行==判断;
// 通常map的key为int、string类型。
// 2 map中value的类型和key的类型一致,可以是bool、int、float、string、map、指针、
// channel、接口、结构体和数组;通常为int、float、string、map和struct。
// 3 map的声明语法,var 变量名 map[keyType]valueType;
// 声明一个map是不会分配内存的,只有使用make初始化后才会分配内存;
// 分配内存后才能赋值和使用。
// 3.1 声明一个map
var a1 map[int]string
// 3.2 使用make初始化map会给map分配内存,map在使用前必须使用make分配内存。
a1 = make(map[int]string, 1)
a1[1] = "tom"
a1[2] = "alice"
fmt.Println(a1) // map[1:tom 2:alice]
// 3.3 声明的map的value类型是map
var a2 map[string]map[int]string
a2 = make(map[string]map[int]string, 1)
a2["one"] = a1
fmt.Println(a2) // map[one:map[1:tom 2:alice]]
// 4 map的使用。
// 4.1 map的第一种使用方式。
var a3 map[int]string
a3 = make(map[int]string, 1)
a3[1] = "a1"
a3[2] = "a2"
fmt.Println(a3) //
// 4.2 map的第二种使用方式。
a4 := make(map[string]int)
a4["one"] = 1
a4["two"] = 2
fmt.Println(a4) // map[one:1 two:2]
// 4.3 map的第三种使用方式。
a5 := map[string]string {
"1": "tom",
"2": "alice",
}
a5["3"] = "bob"
fmt.Println(a5) // map[1:tom 2:alice 3:bob]
8.map的增删改查操作
// 1 map的增加和更新,如果map中没有key则是增加操作;如果map中有key则是更新操作。
a1 := make(map[string]string, 10)
a1["a"] = "alice" // 增加
a1["b"] = "bob" // 增加
a1["a"] = "tom" // 更新
fmt.Println(a1) // map[a:tom b:bob]
// 2 map的删除需要使用内置函数delete。delete函数需要传入map和要删除的key。
// 如果这个key存在则删除当前key;如果key不存在,不进行操作,也不会报错。
// 3 删除map中key的两种方式:遍历map的key,逐个删除;
// 将当前map设置为空,等待垃圾回收,如a2 = nil。
a2 := make(map[string]string)
a2["1"] = "a1"
a2["2"] = "a2"
fmt.Println(a2) // map[1:a1 2:a2]
// delete删除map的key。
delete(a2, "2")
fmt.Println(a2) // map[1:a1]
// 删除不存的key不会报错。
delete(a2, "3")
// 3 map的查找。map的查找会返回两个参数,查找的值和bool类型的是否查找到。
// 如果找到则返回查找到的值和true;如果没有找到则返回value类型的默认值和false。
a3 := make(map[string]int, 1)
a3["a1"] = 1
a3["a2"] = 2
a3["a3"] = 3
i, ok := a3["a2"]
// 查找到了
if ok {
fmt.Println("查找到了")
}
fmt.Println(i, ok) // 2 true
i, ok = a3["a4"]
fmt.Println(i, ok) // 0 false
// 4 map的遍历。
a4 := make(map[string]string)
a4["1"] = "a1"
a4["2"] = "a2"
// 2 a2 == 1 a1
for key, value := range a4 {
fmt.Println(key, value)
}
// 5 计算map的长度。使用内置函数len()计算map的长度。
a5 := make(map[string]string)
a5["1"] = "a1"
a5["2"] = "a2"
fmt.Println(len(a5)) // 2
9.map的其他操作
- map切片。
// 1 切片的类型如果是map,则成为slice of map,map切片,这样map的个数就可以动态变化了。
// 2 声明map切片。
var a1 []map[string]int
a1 = make([]map[string]int, 2)
// 给a1[0]分配空间,并进行初始化。
a1[0] = make(map[string]int, 1)
a1[0]["tom"] = 1
// 给a1[1]分配空间,并进行初始化。
a1[1] = make(map[string]int, 1)
a1[1]["alice"] = 2
// 给a1[2]分配空间,并进行初始化。
// 此时会报错:panic: runtime error: index out of range [2] with length 2
// 因为map切片的长度是2,如果想动态扩容,可以使用切片的append()函数。
// a1[2] = make(map[string]int, 1)
// a1[2]["tom"] = 1
map1 := map[string]int {
"tom": 1,
}
fmt.Println(a1) // [map[tom:1] map[alice:2]]
a1 = append(a1, map1)
fmt.Println(a1) // [map[tom:1] map[alice:2] map[tom:1]]
- map排序。
// 1 map默认是无序的,map的输出不会按照添加顺序输出。
a1 := map[int]int {
10: 100,
1: 10,
4: 20,
8: 30,
}
fmt.Println(a1) // map[1:10 4:20 8:30 10:100]
fmt.Println(a1) // map[1:10 4:20 8:30 10:100]
// 2 如果想按照map的key顺序输出key,则需要先key放入到切片中,然后对切片进行排序,
// 最后遍历切片,按照key输出map的值。
a2 := map[int]int {
10: 100,
1: 10,
4: 20,
8: 30,
}
// 将map的key放入切片中。
var a3 []int
for key, _ := range a2 {
a3 = append(a3, key)
}
// 对切片进行排序。
sort.Ints(a3)
// 遍历切片。
// 10 20 30 100
for _, value := range a3 {
fmt.Println(a2[value])
}
- map的使用细节。
// 1 向map中增加元素时,当超过map的容量后,会触发map的自动扩容,
// 不会发生panic,即map可以动态增长。
// 2 map获取数据。当map的value是一个map时,如果没有查找到可以通过nil判断,
// 即引用类型的默认值为nil。
a1 := make(map[string]map[string]int, 2)
a2 := a1["a1"]
fmt.Println(a2) // map[]
// a2 == nil
if a2 == nil {
fmt.Println("a2 == nil")
}
a3 := make(map[string]string)
a4 := a3["a1"]
fmt.Println(a4)
// 当map的value是值类型时,不能通过nil判断是否为空,否则报错。
// 报错:invalid operation: a4 == nil (mismatched types string and untyped nil)
/*
if a4 == nil {
fmt.Println()
}
*/
标签:map,a1,int,Go04,切片,a2,Println,fmt
From: https://www.cnblogs.com/godistance/p/17258514.html