GO语言map实战

本文详细介绍了Go语言中Map的使用,包括Map的语法、Key的数据类型限制及示例,以及Map的基本操作如创建、增删改查和遍历。此外,还探讨了Go语言字符串的特性,特别是UTF-8编码下的长度计算和遍历方法。
摘要由CSDN通过智能技术生成

1.1 map语法

◼ go中的map是hash表的一个引用,类型写为:map[key]value,其中的key, value分别对应一种数据类型,如map[string]string
◼ 要求所有的key的数据类型相同,所有value数据类型相同(注:key与value可以有不同的数据类型,如果想不同则使用interface作为value)map中的key的数据类型
◼ map中的每个key在keys的集合中是唯一的,而且需要支持 == or != 操作
◼ key的常用类型:int, rune, string, 结构体(每个元素需要支持 == or != 操作), 指针, 基于这些类型自定义的类型

float32/64 类型从语法上可以作为key类型,但是实际一般不作为key,因为其类型有误差
1.2 key的几种数据类型举例

package main

import "fmt"

func main() {
	// m0 可以, key类型为string, 支持 == 比较操作
	{
		fmt.Println("---- m0 ----")
		var m0 map[string]string // 定义map类型变量m0,key的类型为string,value的类型string
		fmt.Println(m0)
	}

	// m1 不可以, []byte是slice,不支持 == != 操作,不可以作为map key的数据类型
	{
		// fmt.Println("---- m1 ----");
		//var m1 map[[]byte]string // 报错: invalid map key type []byte
		//fmt.Println(m1)

		// 准确说slice类型只能与nil比较,其他的都不可以,可以通过如下测试:
		// var b1,b2 []byte
		// fmt.Println(b1==b2) // 报错: invalid operation: b1 == b2 (slice can only be compared to nil)
	}

	// m2 可以, interface{}类型可以作为key,但是需要加入的key的类型是可以比较的
	{
		fmt.Println("---- m2 ----")
		var m2 map[interface{}]string
		m2 = make(map[interface{}]string)
		//m2[[]byte("k2")]="v2" // panic: runtime error: hash of unhashable type []uint8
		m2[123] = "123"
		m2[12.3] = "123"
		fmt.Println(m2)

		var str string = m2[12.3]
		fmt.Println(str)
	}

	// m3 可以, 数组支持比较
	{
		fmt.Println("---- m3 ----")
		a3 := [3]int{1, 2, 3}
		var m3 map[[3]int]string
		m3 = make(map[[3]int]string)
		m3[a3] = "m3"
		fmt.Println(m3)
	}

	// m4 可以,book1里面的元素都是支持== !=
	{
		fmt.Println("---- m4 ----")
		type book1 struct {
			name string
		}
		var m4 map[book1]string
		fmt.Println(m4)
	}

	// m5 不可以, text元素类型为[]byte, 不满足key的要求
	{
		fmt.Println("---- m5 ----")
		//type book2 struct {
		//	name string
		//	text []byte //没有这个就可以
		//}
		//var m5 map[book2]string //invalid map key type book2
		//fmt.Println(m5)
	}
}

1.3 map的基本操作

map创建

两种创建的方式:一是通过字面值;二是通过make函数

map增删改查

增加,修改: m["c"] = "11": v1 := m["x"]
v2, ok2 := m["x"]: delete(m, "x")

map遍历

•遍历的顺序是随机的
•使用for range遍历的时候,k,v使用的同一块内存,这也是容易出现错误的地方
for k, v := range m { fmt.Printf("k:[%v].v:[%v]\n", k, v) //
输出k,v值 }

example:

// 4-2 map基本操作
package main

import "fmt"

func create() {
	fmt.Println("map创建方式:")
	// 1 字面值
	{
		m1 := map[string]string{
			"m1": "v1", // 定义时指定的初始key/value, 后面可以继续添加
		}
		_ = m1

	}

	// 2 使用make函数
	{
		m2 := make(map[string]string) // 创建时,里面不含元素,元素都需要后续添加
		m2["m2"] = "v2"               // 添加元素
		_ = m2

	}

	// 定义一个空的map
	{
		m3 := map[string]string{}
		m4 := make(map[string]string)
		_ = m3
		_ = m4
	}
}

func curd() {
	fmt.Println("map增删改查:")
	// 创建
	fmt.Println("建:")
	m := map[string]string{
		"a": "va",
		"b": "vb",
	}
	fmt.Println(len(m)) // len(m) 获得m中key/value对的个数

	// 增加,修改
	fmt.Println("增改:")
	{
		// k不存在为增加,k存在为修改
		m["c"] = ""
		m["c"] = "11"                      // 重复增加(key相同),使用新的值覆盖
		fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"a":"va", "b":"vb", "c":"11"} 3
	}

	// 查
	fmt.Println("查:")
	{
		// v := m[k] // 从m中取键k对应的值给v,如果k在m中不存在,则将value类型的零值赋值给v
		// v, ok := m[k] // 从m中取键k对应的值给v,如果k存在,ok=true,如果k不存在,将value类型的零值赋值给v同时ok=false
		// 查1 - 元素不存在
		v1 := m["x"] //
		v2, ok2 := m["x"]
		fmt.Printf("%#v %#v %#v\n", v1, v2, ok2) // "" "" false

		// 查2 - 元素存在
		v3 := m["a"]
		v4, ok4 := m["a"]
		fmt.Printf("%#v %#v %#v\n", v3, v4, ok4) //"va" "va" true
	}
	fmt.Println("删:")
	// 删, 使用内置函数删除k/v对
	{
		// delete(m, k) 将k以及k对应的v从m中删掉;如果k不在m中,不执行任何操作
		delete(m, "x")                     // 删除不存在的key,原m不影响
		delete(m, "a")                     // 删除存在的key
		fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"b":"vb", "c":"11"} 2
		delete(m, "a")                     // 重复删除不报错,m无影响
		fmt.Printf("%#v %#v\n", m, len(m)) /// map[string]string{"b":"vb", "c":"11"} 2
	}
}

func travel() {
	fmt.Println("map遍历:")
	m := map[string]int{
		"a": 1,
		"b": 2,
	}
	for k, v := range m {
		fmt.Printf("k:[%v].v:[%v]\n", k, v) // 输出k,v值
	}

	var fruits = map[string]int{
		"apple":  2,
		"banana": 5,
		"orange": 8,
	}

	for name, score := range fruits {
		fmt.Println(name, score)
	}

	for name := range fruits {
		fmt.Println(name)
	}
}

func main() {
	create()
	curd()
	travel()
}

1.4 string字符串

字符串通常有两种设计,一种是「字符」串,一种是「字节」串。「字符」串中的每个字都是定长的,而「字节」串中每个字是不定长的。Go 语言里的字符串是「字节」串,英文字符占用 1 个字节,非英文字符占多个字节。
在这里插入图片描述

其中 codepoint 是每个「字」的其实偏移量。Go 语言的字符串采用 utf8 编码,中文汉字通常需要占用 3 个字节,英文只需要 1 个字节。len() 函数得到的是字节的数量,通过下标来访问字符串得到的是「字节」。

(1)字符串遍历:

example1:

// 按字节遍历
package main

import "fmt"

func main() {
	var s = "嘻哈china"
	for i := 0; i < len(s); i++ {
		fmt.Printf("%x ", s[i])
	}

}

结果:e5 98 bb e5 93 88 63 68 69 6e 61

example2:

// 按字符 rune 遍历
package main

import "fmt"

func main() {
	var s = "嘻哈china"
	for codepoint, runeValue := range s {
		fmt.Printf("[%d]: %x", codepoint, int32(runeValue))
	}
}


结果:[0]: 563b[3]: 54c8[6]: 63[7]: 68[8]: 69[9]: 6e[10]: 61

(2)字符传切割和转换

example:

// 按字符 rune 遍历
package main

import "fmt"

func splice() {
	var s1 = "hello" // 静态字面量
	var s2 = ""
	for i := 0; i < 10; i++ {
		s2 += s1 // 动态构造
	}
	fmt.Println(len(s1))
	fmt.Println(len(s2))
}

// 字符串是只读的
//func onlyread() {
//	var s = "hello"
//	s[0] = 'H'
//}

// 切割切割
func cut() {
	var s1 = "hello world"
	var s2 = s1[3:8]
	fmt.Println(s2)
}

// 字节切片和字符串的相互转换
func string2bytes() {
	var s1 = "hello world"
	var b = []byte(s1) // 字符串转字节切片
	var s2 = string(b) // 字节切片转字符串
	fmt.Println(b)
	fmt.Println(s2)
}
func main() {
	splice()
	//onlyread()
	cut()
	string2bytes()
}


执行结果:
5
50
lo wo
[104 101 108 108 111 32 119 111 114 108 100]
hello world

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值