Golang内建容器

数组
package main

import "fmt"

// go语言 数组是值传递,这个函数只能传长度为 5 的int数组,传其他的会报错
func printArr(arr [5]int){
	// 因为是值传递,函数内对修改元素不会影响原始数组
	for i, v := range arr{
		fmt.Println(i, v)
	}
}

// 可以通过传指针来改变数组内的数据,但这里依然需要传指定长度的数组指针
func printArr2(arr *[5]int){
	arr[0] = 100
	fmt.Println(arr)

}

// 可以传切片,这样就不限长度了
func printArr3(arr []int){
	for i, v := range arr{
		fmt.Println(i, v)
	}
}


func main() {
	// 一维数组
	var arr1 [5]int
	arr2 := [5]int{1,2,3,4,5}
	arr3 := [...]int{6,7,8,9,0,1,2,3}
	fmt.Println(arr1, arr2, arr3)
	// 二维
	var grid [4][5]int
	fmt.Println(grid)

	// 遍历1
	for i:= range arr3{
		fmt.Println(i)
	}
	// 遍历2
	for i, v := range arr3{
		fmt.Println(i, v)
	}

	// 遍历3
	for _, v := range arr3{
		fmt.Println(v)
	}

	printArr(arr2)
	printArr2(&arr2)

	// 需要传切片
	printArr3(arr2[:])
	printArr3(arr3[:])
}
切片
package main

import "fmt"

// 传切片的函数
func test(arr []int){
	arr[0] = 100
}

func main() {
	arr := [...]int{1,2,3,4,5}
	fmt.Println("可以用切片代替引用传递")
	fmt.Println("\tarr:", arr)
	test(arr[:])
	fmt.Println("\ttest(arr[:]): 函数内修改数值生效", arr[:], "\n\n")

	// 切片可以向后扩展
	arr1 := [...]int{0,1,2,3,4,5,6,7}
	fmt.Println("切片向后可以扩展, arr1:", arr1)
	s1 := arr1[2:8] // {2, 3, 4, 5}
	s2 := s1[3:5] // 本来应该只能取到 [3:4], 但是原数组中后面其实还有元素,这里并不会报错,而是会自动补齐 {5, 6}
	s3 := s2[2:3] // 同理, 这里是 {6}
	fmt.Println(s1, s2, s3)

	// 添加元素
	s4 := append(s1, 8) // s1 后没有了元素,即添加的位置 > cap, 此时会生成一个新的数组, 不再是视图 {}
	s5 := append(s2, 9) // s2 后 还有个 7, 此处添加,会覆盖原数组的 7
	fmt.Println(s4, s5)


	// 建立切片的其他方式
	var s []int
	fmt.Println(s) // 只是一个空slice, 值为 nil
	//方法二
	s6 := []int{1,2,3,4}
	fmt.Println(s6)
	// 建一个指定长度的slice
	s7 := make([]int, 10) // 初始值都为 0, len= 10, cap = 10
	fmt.Println(s7)
	// 可以指定大一点的cap, 方便扩展
	s8 := make([]int, 10, 12) // len = 10, cap = 12
	fmt.Println(s8)


	// 拷贝 slice
	copy(s8, s6) // 把 s6 拷贝进s8, 效果是,将s6 按顺序插入进 s8
	fmt.Println(s8)

	// 删除中间元素
	//[1 2 3 4 0 0 0 0 0 0]
	// 挺鸡肋的一种方式,操作起来很麻烦
	s8 = append(s8[:3], s8[4:]...)
	fmt.Println(s8)

	// 删除头尾元素
	s6 = []int{1,2,3,4,5}
	s6 = s6[:len(s6)-1] // 删除尾
	s6 = s6[1:] // 删除头
	print("debug")
map
package main

import (
	"fmt"
	"sort"
)

func main() {
	// 定义例子
	m := map[string]string {
		"name": "cccccc",
		"shchool": "bbbb",
		"home_address": "skjdkjk",
	}
	fmt.Println(m)
	// 定义方法二
	m2 := make(map[string]int) // 这样是定义一个空的map
	fmt.Println(m2)

	// 定义方法三
	var m3 map[string]int
	fmt.Println(m3)

	// 遍历 map
	for key, value := range m{
		fmt.Println(key, value)
	}
	// 省略值
	for key := range m{
		fmt.Println(key)
	}
	// 省略 key
	for _, value := range m{
		fmt.Println(value)
	}

	// 获取值
	name := m["name"]
	fmt.Println(name)

	// 获取不存在的key, 不会报错,而是返回空字符串
	test := m["不存在"]
	fmt.Println(test)

	// 判断是否在 map 中
	name2, exist := m["name"]
	fmt.Println(name2, exist) // exist=true
	test1, exist1 := m["不存在"]
	fmt.Println(test1, exist1) // exist1=false
	// 结合if
	if _, ok := m["name"]; ok {
		fmt.Println("存在")
	}

	// 删除元素
	delete(m, "name")
	fmt.Println(m)

	// 添加
	m["city"] = "北京"
	fmt.Println(m)

	// 结合 slice 按序遍历 map
	var s []string
	for key := range m{
		s = append(s, key)
	}
	sort.Strings(s)
	fmt.Println(s)
	for _, v := range s{
		fmt.Println(v, m[v])
	}
}
字符和字符串处理
package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	s := "hello你好啊" // 这个是utf-8编码,字符所占字节是可变化的,英文1字节, 中文3字节
	// 计算这个字符串长度,len(s) = 5 + 3 * 3 = 14, 这里实际上计算的是 字节长度
	fmt.Println(len(s))
	// 可以用按字节打印出来
	for _, b := range []byte(s){
		fmt.Printf("%X ", b)
	}// 68 65 6C 6C 6F E4 BD A0 E5 A5 BD E5 95 8A, 中文是3个字节

	// 标准的 unicode, 即 UCS-2, 每个字符是占用2个字节,即无论英文还是中文,都是2个字节
	fmt.Println("")

	// 按照 字符 打印出来
	for i, ch := range s{
		fmt.Printf("(%d, %X) ", i, ch)
	} // (0, 68) (1, 65) (2, 6C) (3, 6C) (4, 6F) (5, 4F60) (8, 597D) (11, 554A)
	// 打印出来是 8个字符, 中文如 “你” 的字符编码是 4F60, 2个字节
	// 通过debug 可以知道 ch 的数据类型是 int32, int32有个别名,也叫 rune, 是4字节
	// 所以 编译器是将原本 "你" (utf-8编码),解码成3个字节(E4BDA0),转换成了 2个字节的unicode编码(4F60),
	// 然后将这连个字节放到 4个字节的数据类型-rune 中

	fmt.Println("")
	// 使用utf8.RuneCountInString() 可以计算utf8字符串中 的 rune 字符个数
	fmt.Println(utf8.RuneCountInString(s)) // 8
	// 可以正常计算字符数量

	// 总结:将utf8字符串 按 “英文1个字节,中文3个字节” 解码成字节流,
	//然后再编码成 unicode,英文还是1字节,中文3字节变2字节,之后把1字节的英文和2字节的中文,都放入 4字节的 rune 中
	bytes := []byte(s)
	for len(bytes) > 0{
		ch, size := utf8.DecodeRune(bytes) // 取出"第一个"字符的字符编号和所占字节(英文1个,中文3个)
		fmt.Printf("%c", ch)
		bytes = bytes[size:]
	}

	fmt.Println("")
	// 可以直接转成 rune 数组
	for i, ch := range []rune(s){
		fmt.Printf("(%d, %c)", i, ch)
	}
}