1. 字典:
go语言中的字典与C++的map类似,是key-value类型的数据结构。
1.1 数组\切片 与 字典的比较:
数组切片让我们具备了可以操作一块连续内存的能力,它是对同质元素的统一管理。而字典则是对关联性数据的进行操作的数据结构。
1.2 字典的创建:
创建字典可以使用
make
函数,但这种方法创建的字典是空的,长度为零,内部没有任何元素。
如果需要给字典提供初始化的元素,则需要使用另一种创建字典的方式。
字典类型使用
map[key]value
表示。
package main
import"fmt"funcmain(){//method 1: makevar m1 map[int]string=make(map[int]string)
fmt.Println(m1,len(m1))//method 2:var m2 map[int]string=map[int]string{90:"excellent",80:"good",60:"pass",}
fmt.Println(m2,len(m2))}------map[]0map[60:pass 80:good 90:excellent]3
make函数可以传递一个整型值,在创建字典时提前分配好内存,避免字典在长大的过程中要经历的多次扩容操作:
funcmain(){var m map[int]string=make(map[int]string,16)}
1.3 字典的读写:
同C++中的map一样,Go语言中的字典也可以使用中括号来读写内部元素,使用delete函数来删除元素。
package main
import"fmt"funcmain(){var fruits map[string]int=map[string]int{"apple":2,"banana":5,"orange":8,}var price = fruits["apple"]
fmt.Println(price)
fruits["pear"]=3//增加元素
fmt.Println(fruits["pear"])delete(fruits,"pear")//delete删除元素
fmt.Println(fruits)}------23map[apple:2 banana:5 orange:8]
当delete删除操作对应的key不存在时,delete函数会静默处理,delete没有返回值。因此无法直接判断delete操作是否真的删除了某个元素,只能通过判断字典的长度信息 或者提前尝试读取key对应的value。
当读操作时,如果key不存在,也不会抛出异常,它会返回value类型对应的零值。
key和value可能恰好就是零值,所以不能通过读操作的返回值直接判断key是否存在,而是要使用到字典的特殊语法:函数的“多态返回值”(一个函数的返回值可以有多个)。
package main
import"fmt"funcmain(){var fruits map[string]int=map[string]int{"apple":2,"banana":5,"ornage":8,}var price, result = fruits["pear"];if result {
fmt.Println(price)}else{
fmt.Println("key is not exists")}var score, ok = fruits["apple"]if ok {
fmt.Println(score)}else{
fmt.Println("key is not exists")}}------
key is not exists
2
1.4 字典的遍历:
字典的遍历提供两种方式,一种是可以同时获取key和value的值,一种是只获取key的值。
字典的遍历需要使用Go语言的
range
关键字。
package main
import"fmt"funcmain(){var fruits map[string]int=map[string]int{"apple":2,"banana":5,"ornage":8,}//method 1://格式: for key value := range map {}for name, score :=range fruits {
fmt.Println(name, score)}//method 2://格式: for key := range map {}for name :=range fruits {
fmt.Println(name)}}------
apple 2
banana 5
ornage 8
apple
banana
ornage
Go语言的字典没有提供 keys() 和 values() 这样的获取key或者value列表的方法,需要自行循环遍历获取:
package main
import"fmt"funcmain(){var fruits map[string]int=map[string]int{"apple":2,"banana":5,"ornage":8,}var names []string=make([]string,0,len(fruits))var scores []int=make([]int,0,len(fruits))for name, score :=range fruits {
names =append(names, name)
scores =append(scores, score)}
fmt.Println(names)
fmt.Println(scores)}------[apple banana ornage][258]
1.5 线程(协程)安全:
Go语言内置的字典不是线程安全的,如果需要线程安全,必须使用锁来控制。
1.6 字典变量中存放的值:
字典里存放的只是一个地址指针,这个指针指向字典的头部对象。
所以字典占用的空间是一个字,即一个指针的大小,在32位机器上是4个字节,在64位机器上是8个字节。
2. 字符串:
Go语言中的字符串的每个节点是 不定长的,其中 英文字符 占用 1个字节,非英文字符占用多个字节。
这意味着无法通过位置来快速定位出一个完整的字符来,而必须通过遍历的方式来逐个获取单个字符。
Go语言中的字符类型是
rune
,rune是一个衍生类型,在内存中使用 int32 类型的4个字节存储:
typeruneint32
Go语言中的字符串并不是用 rune字符 来实现的,而是一种“字节串”,即按照节点元素的实际大小来分配内存:例如一个英文字符分配 1字节,一个中文字符分配 3字节。
如果使用 字符串 来表示字符串会造成空间浪费,因为所有的英文字符本来只需要一个字节来表示,用 rune 字符来表示的话那么剩余的3个字节都是零。但使用 rune来完全实现字符串有一个好处,那就是可以快速定位节点位置,因为所有节点占用的内存都是等长的。
图示 字节byte 与 字符rune 的区别:
其中,codepoint是每个字的真实偏移量,Go语言的字符采用 utf8 编码,其中中文汉字占用 3个字节,英文字符占用 1个字节。
len() 函数得到的是 字节的数量,通过下标来访问字符串得到的是 字节。
2.1 字符串的内存结构:
字符串的内存结构类似于切片的结构,编译器为其分配了头部字段来存储长度信息和 指向底层字节数组的指针,如下图所示:
当我们将一个字符串赋值给另一个字符串变量时,发生的是浅拷贝,底层的字节数组是共享的,只是浅拷贝了头部字段。
2.2 字符串是只读的:
编译器禁止使用字符串下标来直接赋值,只能通过下标读取字符串上指定位置的字节。
package main
import"fmt"funcmain(){var s ="hello"
fmt.Printf("%c\n", s[0])//正确!输出: h
s[0]='w'//错误!编译器:cannot assign to s[0] (strings are immutable)}
2.3 字符串的切割:
字符串的实现上与切片类似,字符串也同样支持切割操作,切割后子串与母串共享底层的字节数组。
package main
import"fmt"funcmain(){var s1 string="hello world";var s2 string= s1[2:5]
fmt.Println(s1)
fmt.Println(s2)}------
hello world
llo
2.4 字节切片和字符串的相互转换:
在使用Go语言进行网络编程时,经常需要将来自网络的字节流转换成内存字符串,同时也需要将内存字符串转换成网络字节流。Go语言内置了字节切片和字符串的相互转换语法。
package main
import"fmt"funcmain(){var s1 string="hello world"var b []byte=[]byte(s1)//字符串转成字节切片var s2 string=string(b)//字节切片转成字符串
fmt.Println(b)
fmt.Println(s2)}------[10410110810811132119111114108100]
hello world
当字节切片与字符串进行相互转换时,底层字节数组是不共享的,而是会进行拷贝,如果内容很大,那么转换操作需要一定的成本。
转换时需要进行拷贝的原因是:字节切片的底层数组内容是可以进行修改的,而字符串的底层字节数组是只读的,如果共享底层数组,就会导致字符串的只读属性不再成立。
参考内容:
https://zhuanlan.zhihu.com/p/50047198
https://zhuanlan.zhihu.com/p/50399072
版权归原作者 windsofchange 所有, 如有侵权,请联系我们删除。