0


go语言:字典、字符串

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

标签:

本文转载自: https://blog.csdn.net/ArtAndLife/article/details/118946907
版权归原作者 windsofchange 所有, 如有侵权,请联系我们删除。

“go语言:字典、字符串”的评论:

还没有评论