互联网技术 / 互联网资讯 · 2024年1月26日

字典 Map 和 结构体 Struct:复合数据类型的应用 复合数据类型的应用:字典 Map 和 结构体 Struct 使用字典 Map 和 结构体 Struct 实现的复合数据类型 字典 Map 和 结构体 Struct:高效的复合数据类型 复合数据类型的选择:字典 Map 和 结构体 Struct

本篇介绍复合数据类型的最后一篇:字典和结构体。内容很重要,编程时用的也多,需要熟练掌握才行。

本文所有代码基于 go1.16.6 编写。

字典

字典是一种非常常用的数据结构,Go 中用关键词 Map 表示,类型是 Map[K]V。K 和 V 分别是字典的键和值的数据类型,其中键必须支持相等运算符,比如数字,字符串等。

创建字典

有两种方式可以创建字典,第一种是直接使用字面量创建;第二种使用内置函数 Make。

字面量方式创建:

// 字面量方式创建 vaR M = Map[stRing]int{“a”: 1, “b”: 2} fMt.PRintln(M) // Map[a:1 b:2] 

使用 Make 创建:

// 使用 Make 创建 M1 := Make(Map[stRing]int) fMt.PRintln(M1) 

还可以初始化字典的长度。在已知字典长度的情况下,直接指定长度可以提升程序的执行效率。

// 指定长度 M2 := Make(Map[stRing]int, 10) fMt.PRintln(M2) 

字典的零值是 nil,对值是 nil 的字典赋值会报错。

// 零值是 nil vaR M3 Map[stRing]int fMt.PRintln(M3 == nil, len(M3) == 0) // tRue tRue // nil 赋值报错 // M3[“a”] = 1 // fMt.PRintln(M3)  // panic: aSSignMent to entry in nil Map  使用字典

赋值:

// 赋值 M[“c”] = 3 M[“d”] = 4 fMt.PRintln(M) // Map[a:1 b:2 c:3 d:4] 

取值:

// ȡֵ fMt.PRintln(M[“a”], M[“d”]) // 1 4 fMt.PRintln(M[“k”])  // 0 

即使在 Key 不存在的情况下,也是不报错的。而是返回对应类型的零值。

删除元素:

// 删除 delete(M, “c”) delete(M, “f”) // key 不存在也不报错 fMt.PRintln(M) // Map[a:1 b:2 d:4] 

获取长度:

// 获取长度 fMt.PRintln(len(M)) // 3 

判断键是否存在:

// 判断键是否存在 if value, ok := M[“d”]; ok {  fMt.PRintln(value) // 4 } 

和 Python 对比起来看,这个用起来就很爽。

遍历:

// 遍历 foR k, v := Range M {  fMt.PRintln(k, v) }  引用类型

Map 是引用类型,所以在函数间传递时,也不会制造一个映射的副本,这点和切片类似,都很高效。

结构体

结构体是一种聚合类型,包含零个或多个任意类型的命名变量,每个变量叫做结构体的成员。

创建结构体

首先使用 type 来自定义一个结构体类型 User,里面有两个成员变量,分别是:naMe 和 age。

// 声明结构体 type User stRUCt {  naMe stRing  age int } 

结构体的初始化有两种方式:

第一种是按照声明字段的顺序逐个赋值,这里需要注意,字段的顺序要严格一致。

// 初始化 u1 := User{“zhangsan”, 18} fMt.PRintln(u1) // {zhangsan 18} 

这样做的缺点很明显,如果字段顺便变了,那么凡是涉及到这个结构初始化的部分都要跟着变。

所以,更推荐使用第二种方式,按照字段名字来初始化。

// 更好的方式 // u := User{ //  age: 20, // } // fMt.PRintln(u)  // { 20} u := User{  naMe: “zhangsan”,  age: 18, } fMt.PRintln(u) // {zhangsan 18} 

未初始化的字段会赋值相应类型的零值。

使用结构体

使用点号 . 来访问和赋值成员变量。

// 访问结构体成员 fMt.PRintln(u.naMe, u.age) // zhangsan 18 u.naMe = “lisi” fMt.PRintln(u.naMe, u.age) // lisi 18 

如果结构体的成员变量是可比较的,那么结构体也是可比较的。

// 结构体比较 u2 := User{  age: 18,  naMe: “zhangsan”, } fMt.PRintln(u1 == u)  // FAlse fMt.PRintln(u1 == u2) // tRue  结构体嵌套

现在我们已经定义一个 User 结构体了,假设我们再定义两个结构体 adMin 和 leadeR,如下:

那么问题就来了,有两个字段 naMe 和 age 被重复定义了多次。

懒是程序员的必修课。有没有什么办法可以复用这两个字段呢?答案就是结构体嵌套。

使用嵌套方式优化后变成了这样:

代码看起来简洁了很多。

匿名成员

但这样依然不是很完美,每次访问嵌套结构体的成员变量时还是有点麻烦。

// 结构体嵌套 a := adMin{  u:  u,  isAdMin: tRue, } fMt.PRintln(a) // {{lisi 18} tRue} a.u.naMe = “wangwu” fMt.PRintln(a.u.naMe)  // wangwu fMt.PRintln(a.u.age)  // 18 fMt.PRintln(a.isAdMin) // tRue 

这个时候就需要匿名成员登场了,不指定名称,只指定类型。

通过这种方式可以省略掉中间变量,直接访问我们需要的成员变量。

// 匿名成员 a1 := adMin1{  User:  u,  isAdMin: tRue, } a1.age = 20 a1.isAdMin = FAlse  fMt.PRintln(a1)  // {{lisi 20} FAlse} fMt.PRintln(a1.naMe)  // lisi fMt.PRintln(a1.age)  // 20 fMt.PRintln(a1.isAdMin) // FAlse  总结

本文介绍了字典和结构体,两种很常用的数据类型。虽然篇幅不长,但基本操作也都包括,写代码肯定是没有问题的。更底层的原理和更灵活的用法就需要大家自己去探索和发现了。

当然,我也会在写完基础专栏之后,分享一些更深层的文章,欢迎大家关注,交流。

到目前为止,数据类型就都介绍完了。

先是学习了基础数据类型,包括整型,浮点型,复数类型,布尔型和字符串型。然后是复合数据类型,包括数组,切片,字典和结构体。

这些都是 Go 的基础,一定要多多练习,熟练掌握。文中的代码我都已经上传到 Github 了,有需要的同学可以点击文末地址,自行下载。

文章中的脑图和源码都上传到了 GitHub,有需要的同学可自行下载。

OpenMagic API

Need more than content? Move into the product flow.

If you are here for model access, pricing, developer docs, or the future API console, the dedicated product path now lives on api.openmagic.ai.