其他分享
首页 > 其他分享> > Go-Task5-字典-字符串

Go-Task5-字典-字符串

作者:互联网

字典, 字符串

字典

map是一种较为特殊的数据结构,在任何一种编程语言中都可以看见他的身影,它是一种键值对结构,通过给定的key可以快速获得对应的value。

如何定义字典

func dict1(){
	var m1 map[string]int
	m2 := make(map[int]interface{}, 100)
	m3 := map[string]string{
		"name": "zhangsan",
		"age": "22",
	}
	fmt.Println(m1) // map[]
	fmt.Println(m2) // map[]
	fmt.Println(m3) // map[age:22 name:zhangsan]
}

在定义字典时不需要为其指定容量,因为map是可以动态增长的,但是在可以预知map容量的情况下为了提高程序的效率也最好提前标明程序的容量。需要注意的是,不能使用不能比较的元素作为字典的key,例如数组,切片等。而value可以是任意类型的,如果使用interface{}作为value类型,那么就可以接受各种类型的值,只不过在具体使用的时候需要使用类型断言来判断类型。

字典操作

放入字典

向字典中放入元素也非常简单

func dict2(m3 map[string]string){
	m3["key1"] = "v1"
	m3["key2"] = "v2"
	m3["key3"] = "v3"
	fmt.Println(m3) //map[age:22 key1:v1 key2:v2 key3:v3 name:zhangsan]

	// 插入两个元素key相同会发生什么
	// 会覆盖
	m3["key4"] = "v4"
	m3["key4"] = "same v4"
	fmt.Println(m3) //map[age:22 key1:v1 key2:v2 key3:v3 key4:same v4 name:zhangsan]
}

你可以动手试一下,如果插入的两个元素key相同会发生什么?-> 会覆盖

各种用法

func dict3(m3 map[string]string) {
	// 这里还可以看出 map如果被当成形参传递会影响到实参!!!
	// 通过控制台可以看出这俩地址一致
	fmt.Printf("dict3, m3 的 地址为:%p \n", m3) //dict3, m3 的 地址为:0xc000078360
	// 获取长度 与数组和切片一样,我们可以使用len来获取字典的长度
	fmt.Println(len(m3)) //

	// 确定键值是否存在
	// 在有些情况下,我们不能确定键值对是否存在,或者当前value存储的是否就是空值,go语言中我们可以通过下面这种方式很简便的进行判断。
	if value, ok := m3["name"]; ok { //存在
		fmt.Println("存在" ,value)
	}
	if value, ok := m3["Hello"]; !ok { //不存在
		fmt.Println("不存在", value)
	}
	// 上面这段代码的作用就是如果当前字典中存在key为name的字符串则取出对应的value,并返回true,否则返回false。

	// 遍历字典
	// 第一遍
	fmt.Println("第一次遍历")
	for key, value := range m3 {
		fmt.Printf("key: %s, value: %s\n", key, value)
	}
	// 第二遍
	fmt.Println("第二次遍历")
	for key, value := range m3 {
		fmt.Printf("key: %s, value: %s\n", key, value)
	}
	// 如果多运行几次上面的这段程序会发现每次的输出顺序并不相同,对于一个字典来说其默认是无序的
	// 有序遍历
	// 		获取key
	keys := make([]string, 0, len(m3))
	for key := range m3 {
		keys = append(keys, key)
	}
	// 对keys 排序(字典序排序), 使得其保持顺序
	sort.Strings(keys) // 记得import sort
	for index, key := range keys { // 根据索引输出
		fmt.Printf("index: %d key: %s value: %s\n", index, key, m3[key])
	}

	// 删除键值对
	if value, ok := m3["key4"]; ok{
		fmt.Println("删除前: ", value)
	}
	delete(m3, "key4")
	if value, ok := m3["key4"]; !ok{
		fmt.Println("删除前: ", value)
	}
}

不仅如此我们还可以将函数作为值类型存入到字典中。

func dict4(){
	// 确实没想到, 但是这个具体在什么情况下会用到呢?
	m := make(map[string]func(a, b int) int)
	m["add"] = func(a, b int) int {
		return a + b
	}
	m["multi"] = func(a, b int) int {
		return a * b
	}
	fmt.Println(m["add"](3, 2))
	fmt.Println(m["multi"](3, 2))
}

字符串

字符串应该可以说是所有编程语言中最为常用的一种数据类型,接下来我们就一起探索下go语言中对于字符串的常用操作方式。

字符串定义

字符串是一种值类型,在创建字符串之后其值是不可变的,也就是说下面这样操作是不允许的。

func string1(){
	Hello := "Hello 1"
	// Hello[6] = '2' - >  不被允许的操作(值不可变)
	fmt.Println(Hello)
}

编译器会提示cannot assign to s[0]。在C语言中字符串是通过\0来标识字符串的结束,而go语言中是通过长度来标识字符串是否结束的。

如果我们想要修改一个字符串的内容,我们可以将其转换为字节切片,再将其转换为字符串,但是也同样需要重新分配内存。

func string1(){
	Hello := "Hello 1"
	// Hello[6] = '2' - >  不被允许的操作(值不可变)
	fmt.Println(Hello) // Hello 1
	// 修改方法
	HelloCopy := []byte(Hello)
	HelloCopy[6] = '2'
	HelloCopy2 := string(HelloCopy)
	fmt.Println(HelloCopy2) // Hello 2
}

与其他数据类型一样也可以通过len函数来获取字符串长度。

len(s)

但是如果字符串中包含中文就不能直接使用byte切片对其进行操作,go语言中我们可以通过这种方式

func string2(){
	s := "你好, 我是go天才小组的成员"
	fmt.Println(len(s)) //37 -> 显然分割的就不太对
	fmt.Println(utf8.RuneCountInString(s)) //15

	b := []byte(s)
	for i := 0; i < len(b); i++ {
		fmt.Printf("%c", b[i])
	} //ä½ å¥½, 我是go天才小组的成员
	fmt.Println()

	r := []rune(s)
	for i := 0; i < len(r); i++ {
		fmt.Printf("%c", r[i])
	} //你好, 我是go天才小组的成员
}

在go语言中字符串都是以utf-8的编码格式进行存储的,所以每个中文占三个字节加上hello的5个字节所以长度为17,如果我们通过utf8.RuneCountInString函数获得的包含中文的字符串长度则与我们的直觉相符合。而且由于中文对于每个单独的字节来说是不可打印的,所以可以看到很多奇怪的输出,但是将字符串转为rune切片则没有问题。

以下内容很详细, 就按照官方的来了, 具体需要用哪些查文档就行

strings包

strings包提供了许多操作字符串的函数。在这里你可以看到都包含哪些函数https://golang.org/pkg/strings/。

下面演示几个例子:

func main() {
	var str string = "This is an example of a string"
	//判断字符串是否以Th开头
	fmt.Printf("%t\n", strings.HasPrefix(str, "Th"))
	//判断字符串是否以aa结尾
	fmt.Printf("%t\n", strings.HasSuffix(str, "aa"))
	//判断字符串是否包含an子串
	fmt.Printf("%t\n", strings.Contains(str, "an"))
}

strconv包

strconv包实现了基本数据类型与字符串之间的转换。在这里你可以看到都包含哪些函数https://golang.org/pkg/strconv/。

下面演示几个例子:

i, err := strconv.Atoi("-42") //将字符串转为int类型
s := strconv.Itoa(-42) //将int类型转为字符串

若转换失败则返回对应的error值。

字符串拼接

除了以上的操作外,字符串拼接也是很常用的一种操作,在go语言中有多种方式可以实现字符串的拼接,但是每个方式的效率并不相同,下面就对这几种方法进行对比。(关于测试的内容会放在后面的章节进行讲解,这里大家只要知道这些拼接方式即可)

1.SPrintf

const numbers = 100

func BenchmarkSprintf(b *testing.B) {
	b.ResetTimer()
	for idx := 0; idx < b.N; idx++ {
		var s string
		for i := 0; i < numbers; i++ {
			s = fmt.Sprintf("%v%v", s, i)
		}
	}
	b.StopTimer()
}

2.+拼接

func BenchmarkStringAdd(b *testing.B) {
	b.ResetTimer()
	for idx := 0; idx < b.N; idx++ {
		var s string
		for i := 0; i < numbers; i++ {
			s += strconv.Itoa(i)
		}
	}
	b.StopTimer()
}

3.bytes.Buffer

func BenchmarkBytesBuf(b *testing.B) {
	b.ResetTimer()
	for idx := 0; idx < b.N; idx++ {
		var buf bytes.Buffer
		for i := 0; i < numbers; i++ {
			buf.WriteString(strconv.Itoa(i))
		}
		_ = buf.String()
	}
	b.StopTimer()
}

4.strings.Builder拼接

func BenchmarkStringBuilder(b *testing.B) {
	b.ResetTimer()
	for idx := 0; idx < b.N; idx++ {
		var builder strings.Builder
		for i := 0; i < numbers; i++ {
			builder.WriteString(strconv.Itoa(i))
		}
		_ = builder.String()
	}
	b.StopTimer()
}

5.对比

BenchmarkSprintf-8         	   68277	     18431 ns/op
BenchmarkStringBuilder-8   	 1302448	       922 ns/op
BenchmarkBytesBuf-8        	  884354	      1264 ns/op
BenchmarkStringAdd-8       	  208486	      5703 ns/op

可以看到通过strings.Builder拼接字符串是最高效的。

标签:Println,Task5,fmt,value,key,字符串,m3,Go,字典
来源: https://blog.csdn.net/qq_38842456/article/details/111384384