《Go语言学习笔记》(雨痕)电子书网盘下载免费在线阅读
成都创新互联公司一直秉承“诚信做人,踏实做事”的原则,不欺瞒客户,是我们最起码的底线! 以服务为基础,以质量求生存,以技术求发展,成交一个客户多一个朋友!为您提供做网站、网站建设、成都网页设计、微信平台小程序开发、成都网站开发、成都网站制作、成都软件开发、重庆APP软件开发是成都本地专业的网站建设和网站设计公司,等你一起来见证!
链接:
提取码:qyzq
书名:Go语言学习笔记
豆瓣评分:8.1
作者: 雨痕
出版社: 电子工业出版社
出品方: 博文视点
出版年: 2016-6
页数: 468
内容简介
作为时下流行的一种系统编程语言,Go 简单易学,性能很好,且支持各类主流平台。已有大量项目采用 Go 编写,这其中就包括 Docker 等明星作品,其开发和执行效率早已被证明。本书经四年多逐步完善,内容覆盖了语言、运行时、性能优化、工具链等各层面知识。且内容经大量读者反馈和校对,没有明显的缺陷和错误。上卷细致解析了语言规范相关细节,便于读者深入理解语言相关功能的使用方法和注意事项。下卷则对运行时源码做出深度剖析,引导读者透彻了解语言功能背后的支持环境和运行体系,诸如内存分配、垃圾回收和并发调度等。本书不适合编程初学入门,可供有实际编程经验或正在使用Go 工作的人群参考。
作者简介
自 1996 年从事计算机软件开发工作以来,已 20 春秋。期间供职于北大方正、西单电子商务、九城数码、知乎等公司。主要从事核心开发、架构设计,以及部分管理工作。
1、值接收者和指针接收者
所谓指针接收者和值接收者这两个概念,用GO写了一阵子代码的人都了解了,这里只做简要说明一下,也就是对于一个给定结构,咱们对结构进行方法包装的时候,固定必传的参数,用来指向这个对象结构自身的一个参数,在go中也就是形式如下:
我们对结构体testStruct进行了包装,提供了两个方法,sum和modify,其中sum的方法接收者为a testStruct,这个就是值接收者,而modify的接收者为a *testStruct就是指针接收者,也就是说固定对象指针,一个传递的是指针地址,而另外一个直接传递的是结构值拷贝了
对指针有一定了解的,都可以知道,指针传递过去的,可以直接修改结构内部内容,而值传递过去的,无论如何修改这个接收者的数据,不会对原对象结构产生影响。而对于咱们包装结构对象的时候,到底是使用指针还是使用值接收者,这个实际上没有太大的定论,就我个人的观点来说,如果结构体占有的内存空间不大(kb级别),而又不需要修改内部的,同时结构对象内部没有同步对象比如(sync包中的mutex,rwlock,waitgroup等之类的结构的话,可以直接值传递,实际上值copy也没有咱们想象的那么慢,很多时候,都用指针,最后的gc回收扫描可能都比咱们这个传递copy的消耗大) p="" /kb级别),而又不需要修改内部的,同时结构对象内部没有同步对象比如(sync包中的mutex,rwlock,waitgroup等之类的结构的话,可以直接值传递,实际上值copy也没有咱们想象的那么慢,很多时候,都用指针,最后的gc回收扫描可能都比咱们这个传递copy的消耗大)
2、实现接口的值接收者和指针接收者有啥区别
也就是比如定义如下
这里面的值接收者和指针接收者有什么区别,这里咱来写一个测试
通过这个测试用例可以发现,指针接收者实现的接口可以同时支持转移到值接收者接口和指针接收者接口,而用值接收者实现的接口,则无法转移到使用指针接收者实现的接口,为啥子呢?目前网上或者各类资料上都是给的一个很官方很官方,而且很书面话难以理解的说明,大致意思如下:
这是目前网络或者各种资料上都是差不多是这样说的,看似讲了,实际上就说了一个结果,根本就没说出来一个为什么。这样的总结出来,一个初学者的角度来看,是很不好理解的,初学者要么就是死记硬背,要么就是生搬硬套,甚至直到写了好多好多代码了,都还没有搞明白一个为啥子,只是会用了而已,从长远来说这是不利于自身提高的。
有这两个本质点,咱们自己来思考一下,如果你来实现这个编译器的时候,用指针接收的时候,指针接收者,默认就能直接获取支持,而值接收者实现接口的咱们可以直接来一个解指针就变成了值,就能匹配上值接收者实现的接口了,反过来说,如果值接收者,此时要匹配指针接收者,如何匹配呢,取一个地址就变成了指针了,此时数据类型确实是匹配了,但是,地址指向的数据区不对了,因为我们刚刚说了值接收者拷贝了一个新值之后是完全的一个新的对象,这个新对象和原始对象一点关系都没有,咱们取地址,取的也是这个新对象地址,对这个地址进行操作,也是这个新对象的内部数据,和原始数据内部没有任何关系,所以由此就能推断出,这个是为啥子值接收者不能匹配上指针接收者,而指针接收者却可以匹配上值接收者了。
1、在某个作用域内部,所有定义的字符串的数据区相同
这个很好验证,代码如下:
2、字符串相加会产生一个新串
这个也很好验证
3、字符串真的是不可变的吗
实际上从字符串的结构
从这个结构,就能大致的推断出来,字符串设计成这样就不具备直接扩容+来增加新数据,而如果咱们直接使用string[index] = 'a',用这种方式,就不能编译通过,官方也确定说字符串是不可变的。那么真的是不可变的吗?
通过上面的结构,在加上go的slice切片的数据结构
由此可见,咱们可以将字符串通过指针方式强转为一个byte数组指针,然后通过byte切片来修改,试试
编译通过,运行报错
unexpected fault address 0xae2e27
fatal error: fault
这个错误,基本上就是一个内存的保护错误,是写异常,所以说明了,这个肯定做了内存写保护,那么直接修改一下内存区的属性,去掉他的写保护,就能写了
以下代码都是在Win平台,Go1.18,Win上修改内存权限属性,使用VirtualProtect,代码如下
此时运行,就能发现tstr的内容被咱们变了,这种情况实际上在实际开发中不具有实际意义,因为本身在语言层面,已经做了层层限制,咱们这是属于非法强制的操作方式,是流氓行为,那么是否有比较温和一点的操作方式呢?答案是有的,且往下看。
通过上面,我们已经用到了字符串结构,切片结构,要想字符串内容可变,那么咱们自己构造字符串的数据内容区域,且让这个数据区木有内存写保护不就行了,内容区可变,GO原生态的byte数组不就行嘛,所以咱们自己构造一下
此时我们直接修改buffer的内容,就是直接修改了str的数据内容了。而又不会像前面的一样遇到内存写保护
4、字符串转换优化时可能碰到的坑
通过前面讨论的字符串的可变性的方法,咱们可以知道,很多时候,[]byte到字符串的转变,可以直接构造其结构,而共享数据,从而达到减少数据内存copy的方式来进行优化,再使用这些优化的时候,一定需要注意,字符串或者数组的生命周期,是否会存在被改写的情况,从而导致前后不一致的问题。
比如下面这段代码:
大家可以猜想一下,这个最后里面的数据mmp中,"test"的value是多少,"abcd"的value是多少,然后想想为什么,且等端午之后,再来分解
本文介绍一些Go语言的基础语法。
先来看一个简单的go语言代码:
go语言的注释方法:
代码执行结果:
下面来进一步介绍go的基础语法。
go语言中格式化输出可以使用 fmt 和 log 这两个标准库,
常用方法:
示例代码:
执行结果:
更多格式化方法可以访问中的fmt包。
log包实现了简单的日志服务,也提供了一些格式化输出的方法。
执行结果:
下面来介绍一下go的数据类型
下表列出了go语言的数据类型:
int、float、bool、string、数组和struct属于值类型,这些类型的变量直接指向存在内存中的值;slice、map、chan、pointer等是引用类型,存储的是一个地址,这个地址存储最终的值。
常量是在程序编译时就确定下来的值,程序运行时无法改变。
执行结果:
执行结果:
Go 语言的运算符主要包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符以及指针相关运算符。
算术运算符:
关系运算符:
逻辑运算符:
位运算符:
赋值运算符:
指针相关运算符:
下面介绍一下go语言中的if语句和switch语句。另外还有一种控制语句叫select语句,通常与通道联用,这里不做介绍。
if语法格式如下:
if ... else :
else if:
示例代码:
语法格式:
另外,添加 fallthrough 会强制执行后面的 case 语句,不管下一条case语句是否为true。
示例代码:
执行结果:
下面介绍几种循环语句:
执行结果:
执行结果:
也可以通过标记退出循环:
--THE END--