2019独角兽企业重金招聘Python工程师标准>>>

上一篇 Go圣经-学习笔记之复合类型

下一篇 Go圣经-学习笔记之复合数据结构(三)

map介绍和简单使用

map是一种无序的key/value对的集合,在Go语言中,一个map就是一个hash表的引用。map中的key数据类型必须是可以比较的,不然key的相等性无法校验,也就无法hash到哪个链表了。

map的删除key可以用过builtin内置delete方法:

func delete(s map[Type]Type1 key Type)

map要注意的一点,我在写RBAC构建多叉树的时候遇到过,map中的value元素并不是一个变量,我们不能对value元素做取地址操作,这样做的话,编译直接报错。禁止对map的value元素去地址操作原因在于:

类似于slice动态数组,底层数组可能随时会变化。map的hash链表增长也是动态的,所以随着map中元素的增加,链表上存放的value元素存储的空间也会发生动态的变化,导致之前的value元素存放地址是无效的

所以,map也是不能用来直接比较的。

总结,slice动态数组和map哈希表即取即用,但是在大并发时,map的读写需要手动互斥的,不过再Go1.9版本中引入了sync.map标准库对map的访问时并发安全的。

map的迭代顺序是不确定的,因为开始就提及了map是一种无序的key/value对的集合。我们如果要保证输出的时候要是有序的,可以这样做:

var smap map[Type]Value
var keys = make([]Type, 0, len(smap))
for key := range smap {keys = append(keys, key)
}
sort.Sort(keys)
for _,  key := range keys {fmt.Println(smap[key])
}

首先收集map中的所有key元素,然后对这些key进行排序,然后再遍历key,并获取map中key对应的value元素。保证其输出有序。

这里提到了一个sort标准库:

type Interface interface{Len() int // 数据长度Less(i, j int) bool // 大小比较Swap(i, j int) // 元素交换
}

数据的排序通过获取数据的长度、数据的比较和数据的交换, 就可以实现集合排序。所以我们可以对要排序的数据类型添加这三种行为,就可以使用sort.Sort排序了。这里要注意的地方是,我们可以不直接在Type类型上添加这三个方法。可以定义其他类型,然后把Type数据类型转成定义的类型,就ok。这里举例说明一下:

var keys []Type // 对keys进行排序type TypeSlice []Type
func (p TypeSlice) Len() int {xxx
}
func (p TypeSlice) Less(i, j int) bool {xxx
}
func (p TypeSlice) Swap(i, j int) {xxx
}sort.Sort(TypeSlice(keys)) // 这里的sort原型不是func Sort(v []T) []T的原因:v不会动态增长,所以是安全的

明白会用就ok了。

Set集合

Go语言中没有set集合数据类型,它可以使用map来实现:var s map[Type]bool, 保证集合的数据不重复性。

map中key类型是slice,请绕道走

因为map中的key类型必须是可以比较的,如果想要的key是slice类型,则需要这样绕道走两步:

  • 定义一个辅助函数K,将slice转化为map中对应string类型的key,确保x和y相等时,K(x)==K(y)。
  • 当每次对map操作时,先用辅助函数K将slice转化为string类型的数据,再操作。

这里有一个关键点:x=y时, K(x)==K(y)为true;当x!=y时,K(x)==K(y)为false。用序列化为byte流再加密取前N个字符,作为string类型的数据就可以了,N个字符大小由一般比较熟悉的算法决定。

结构体

结构体 是一种聚合的数据类型,是由零个或者多个任意类型的值聚合成的实体。

由函数返回结构体参数引出的讨论:

func EmployeeById(id int) *Employee {...
}func print() {fmt.Println(EmployeeById(1234).Position) // "管理员"EmployeeById(1234).Position = "销售员" // 这个是合理的。虽然是给返回的参数赋值,它确实可以对原实体有修改的影响
}

上面的DEMO,如果把函数原型改为func EmployeeById(id int) Employee,则编译无法通过。错误在最后一个语句。如果EmployeeById返回参数是一个拷贝的变量,则返回后没有变量名,也就没有任何意义,它会作为垃圾回收处理,我们在《Go圣经-学习笔记之程序结构》有说过,当一个内存地址不再被任何别名引用时,它会被垃圾回收掉。这里你也无法引用它。

由此知道,当返回的参数没有引用其他变量时,则这个新的内存地址没有被任何变量引用,则会被垃圾回收掉, 做赋值操作也就没有任何意义, 所以编译会直接报错。而指针值类型引用了变量,则暂时不会被垃圾回收,修改内存值是由意义的。

结构体嵌入和匿名成员

我们首先看一个圆和一个轮子的结构体定义:

type Point struct {X, Y int
}
type Circle struct { // 圆的定义Center Point Radius int // 半径
}
type Wheel struct { // 轮子的定义Circle Circle // 这里成员变量名称也可以和类型名相同Spokes int // 辐条的数量
}var w Wheel
w.Circle.Center.X = 8
w.Circle.Center.Y = 8
w.Circle.Radius = 5
w.Spokes = 20

上面Wheel变量赋值是很麻烦的。为了简便赋值操作,Go语言提供了一个特性:声明一个成员对应的数据类型而不指明成员的名字,这类成员就叫匿名成员。匿名成员的数据类型可以是命名的数据类型,也可以是命名的数据类型指针。下面改造下:

type Circle struct {PointRadius int
}type Wheel struct {CircleSpokes int
}var w Wheel
w.X = 8
w.Y = 8
w.Radius = 4
w.Spokes = 20

这样赋值方便简单,代码不冗余, 当我们用字面声明时,需要这样做:

var w = Wheel{Circle: Circle{Point:  Point{X: 8, Y: 8},Radius: 5,},Spokes: 20, // NOTE: trailing comma necessary here (and at Radius)}

要注意的一点是,如果在结构体采用匿名成员形式,其中不能有相同的两个匿名成员类型,因为它会有隐式的成员名字,会出现名字冲突。那么为什么我们要在结构体中采用匿名成员呢?

Go语言面向编程思想的核心有一个是组合特性,它通过简单的把匿名成员放在一起,就可以吸纳匿名成员类型所有的方法集,这样就可以实现想要的复杂对象行为,同时也可以修改和管理对象的属性。

转载于:https://my.oschina.net/u/3287304/blog/1555084

Go圣经-学习笔记之复合类型(二)相关推荐

  1. 【C++ Primer】第四章学习笔记 (复合类型)

    一,数组      1,数组只有在定义时候才能使用初始化,不能将一个数组赋给另一个数组.            int  a[4]={1,2,3,4};//正确            int  a[4 ...

  2. Go圣经-学习笔记目录

    2019独角兽企业重金招聘Python工程师标准>>> 第一章 入门 Go圣经-学习笔记入门 Go圣经-学习笔记绪论 Go圣经-学习笔记入门-面试题 Go圣经-学习笔记入门bufio ...

  3. Go圣经-学习笔记之defer和异常处理

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇 Go圣经-学习笔记之函数值(二) 下一篇 Go圣经-学习笔记之方法 可变参数 形参数量可变的函数称为可变参数函数.使用 ...

  4. OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co

    OpenCV学习笔记(四十一)--再看基础数据结构core 记得我在OpenCV学习笔记(四)--新版本的数据结构core里面讲过新版本的数据结构了,可是我再看这部分的时候,我发现我当时实在是看得太马 ...

  5. OpenCV学习笔记(三十一)——让demo在他人电脑跑起来 OpenCV学习笔记(三十二)——制作静态库的demo,没有dll也能hold住 OpenCV学习笔记(三十三)——用haar特征训练自己

    OpenCV学习笔记(三十一)--让demo在他人电脑跑起来 这一节的内容感觉比较土鳖.这从来就是一个老生常谈的问题.学MFC的时候就知道这个事情了,那时候记得老师强调多次,如果写的demo想在人家那 ...

  6. WebGL three.js学习笔记 6种类型的纹理介绍及应用

    WebGL three.js学习笔记 6种类型的纹理介绍及应用 本文所使用到的demo演示: 高光贴图Demo演示 反光效果Demo演示(因为是加载的模型,所以速度会慢) (一)普通纹理 计算机图形学 ...

  7. 《mysql入门圣经》_Go圣经-学习笔记之并发循环

    首先说一个,本来上一篇文章应该是, Go圣经-学习笔记之Channel和Goroutine.写了很长一段,结果被有道云笔记TMD坑惨了,服务掉了,不能拷贝,不能保存.这篇文章就丢了.如果以后有时间,我 ...

  8. OpenCV学习笔记(五十一)——imge stitching图像拼接stitching OpenCV学习笔记(五十二)——号外:OpenCV 2.4.1 又出来了。。。。。 OpenCV学习笔记(五

    OpenCV学习笔记(五十一)--imge stitching图像拼接stitching stitching是OpenCV2.4.0一个新模块,功能是实现图像拼接,所有的相关函数都被封装在Stitch ...

  9. JavaScript学习笔记之数组(二)

    JavaScript学习笔记之数组(二) 1.['1','2','3'].map(parseInt) 输出什么,为什么? ['1','2','3'].map(parseInt)//[1,NaN,NaN ...

最新文章

  1. 树形结构:二叉排列树,二叉搜索树
  2. Selenium_WebDriver操作iFrame日历框和复选框_Java
  3. ClearCase是全球领先的软件配置管理工具
  4. spring mvc 简单的文件上传与下载
  5. 雅黑科技php探针,雅黑PHP探针参数详解
  6. 【Udacity】数据的差异性:值域、IQR、方差和标准差
  7. 本人的Linux系统学习
  8. 用PHOTOSHOP 1寸照片制作方法
  9. 【题解刷题总结】青蛙的约会
  10. 使用jira管理Scrum敏捷项目实战(四)jira自定义电子看板、敏捷看板、KANBAN配置
  11. 堆与栈区别,以及分配内存的快慢
  12. androidQ系统新特性
  13. 企业微信会员销售额达40%的资生堂,能带给我们怎样的数字化增长启示?
  14. 内存控制器与SDRAM_内存接口概念
  15. 深入理解grpc(二):grpc原理
  16. centos8使用podman搭建vulhub
  17. 使用 Python 给图片添加水印,其中一种还是隐形的盲水印呢!
  18. RTM版,即Release To Manufacturing(发布到制造)
  19. php变量值传给html,如何将PHP变量传递给新的HTML页面?
  20. Java进阶之光!mysql解压安装教程windows

热门文章

  1. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(二十八):kafka0.10.1 内置性能测试API用法示例...
  2. T-Sql(一)简单语法
  3. iOS Mac Charels 抓包
  4. 【音乐分享】Let Me Go
  5. Linux使用yum安装时出现The program package-cleanup is found in the yum-utils package.解决方法...
  6. C++指针探讨 (二) 函数指针
  7. 路由跳转的时候地址栏的地址变了 但是页面不变_斐讯路由器如何设置上网 斐讯路由器设置上网方法【图文】...
  8. jpype,jpython调用jar包中jdk的问题.
  9. 做bionic(mips)的人犯错,sigsuspend 死锁
  10. android 4.0 屏蔽home键实现