Go 语言修炼指南
文章平均质量分 88
从 0 开始学习 Go 语言,完成书中所有实例,并结合自己的理解进行扩展。
--Allen--
我知道我不知道。
展开
-
0- Golang 修炼指南
本系列是我的学习笔记,希望大家一起学习,一起进步。如果有错误的地方,及时评论 ^_^. 也可以加群讨论:610441700贡献者:@JovanyWong一、快速入门001 安装 go & 你好,世界 002 go 项目结构 003 渐入渐佳 go 程序 004 统计(一) 005 统计(二) 006 统计(三) 007 绘制三角函数图像(一) 008 绘制三角...原创 2018-02-08 10:05:06 · 3217 阅读 · 4 评论 -
081-反射(Kind)
希望你还能记得反射中的 Type 和 Value 这两个类型。Type 是接口类型,Value 是 Struct 类型;Type 是类型描述,而 Value 是具体的值。这次,我们来看一下 Golang 反射中的另一个重要概念 —— Kind.1. Kind 定义 A Kind represents the specific kind of type that a Type r...原创 2018-09-08 22:11:17 · 1202 阅读 · 0 评论 -
082-反射(结构体字段遍历)
如何知道一个未知结构体包含哪些字段呢?利用反射,可以很容易做到。1. 遍历结构体的 field 和 method还记得 reflect.Type 接口吧,这个接口还包含这 4 个方法:type interface Type { ... NumField() int Field(i int) StructField NumMethod() int ...原创 2018-09-15 13:41:36 · 2773 阅读 · 0 评论 -
083-反射(序列化 json)
想必你已经掌握了反射的相关操作,也能够遍历结构体的字段和方法,现在我们就要进入实战了。1. 问题正如标题所指,我们的目标是能将任意类型的结构体序列化成 json. 对应的 golang 的encoding/jsong 包就是 Marshal 函数, C++ 的 jsoncpp 库来说就是 write 或 fastwrite 方法,对应到 JavaScript 就是 JSON.stringify...原创 2018-10-14 12:22:43 · 1349 阅读 · 0 评论 -
084-反射(通过 reflect.Value 修改值)
前面我们学习了一些关于反射的用法,比如:x := 2// 拿到 x 的 Value 对象a := reflect.ValueOf(x)我们可以通过 a 来得知 x 的具体值是多少,那有没有办法通过 a 来修改 x 的值呢?在上面这个例子中,是不行的。1. 可修改性或者说叫可设置性。Value 有一个方法,CanSet,它可以告知你是否可以设置值。还有一个方法就一并讲了,叫 CanA...原创 2018-10-14 13:17:13 · 2087 阅读 · 0 评论 -
085-包的匿名导入(Blank Import)
转眼间,Golang 的博客从春天写到了冬天,现在我们又回到了原点,不忘初心。那时候我们为了匆匆进入 Golang 的世界,几笔掠过了 Golang 项目结构的相关知识,也粗略的介绍了 Golang 的包相关的概念——《go 项目结构》。我们依靠这点知识,撑到了现在。如今,是时候再为你扩展一些关于 Golang 包以及相关的工具了。1. 介绍一路走来,你一定遇到过这样的情况:如果 import...原创 2018-10-20 12:30:07 · 2262 阅读 · 1 评论 -
072-火箭发射游戏(select 关键字)
不知不觉,Golang 之路已经走过了一大半。谢谢所有读者一路陪伴,也很欣慰你们能一直坚持下来。接下来,我们进入几篇比较轻松的话题,我不打算在这里全盘托出,让我们从一个火箭发射小游戏开始吧。同样,这个例子来源于《Golang 程序设计》。1. 小小发射器当然,我们并不是真的要开发一套火箭发射程序的代码,只是简单的模拟一下。这对你来说几乎就是小学生的作业。我们的目标如下:从 10 ...原创 2018-07-11 00:22:53 · 1732 阅读 · 0 评论 -
073-取消并发请求
在服务器开发领域,有很多未知的原因可能导致用户的请求失败。比如:你的服务器并发请求了多个下游服务,并在等待它们返回所有结果。但是很不幸,其中一个服务返回了错误,此时其它所有其它请求我们也就没有必要再等待下去了,而是直接返回并告诉用户本次请求失败。上面的场景在服务器开发领域非常常见,处理起来也比较困难。无论你是写 C++ 还是 Java,或是 Nodejs,都不那么容易处理。多说不益,我们使...原创 2018-07-15 00:13:04 · 669 阅读 · 0 评论 -
074-Context
上一篇文章结束我留下了一下小小的悬念,说 Golang 标准库为我们提供了纯天然的取消并发请求的解决方案,在这里我就需要填坑了。1. 取消并发请求为了能让你快速上手 context,我们继续延续上一篇文章的取消并发请求的例子,使用 context 将其改写。如果你不熟悉上一篇的例子,请务必回去再看一遍。package mainimport ( "context" "...原创 2018-07-15 17:53:31 · 487 阅读 · 0 评论 -
075-互斥锁
过去我们在写 C/C++ 程序的时候,总会听到竞争的概念。比如多线程对共享变量的存取,需要加锁才能避免数据不致的问题。在 Golang 中也不例外,多个 Goroutine 存取共享变量,同样也会出现竞争问题。1. 银行转账假设 Alice 有一个银行账户。Alice 会往里存钱,她的好友 Bob 也会转钱给她。用程序来描述应该是这样:package bank// Alice...原创 2018-08-12 20:55:31 · 546 阅读 · 0 评论 -
076-使用通信的方式共享内存
希望你还能记得住这句话: “不要使用共享数据的方式进行通信,而应该使用通信的方式来共享数据。”这一节,我们秉承这一理念,来改写前面的银行账户存款问题。1. 思路使用 channel 对控制共享数据。不要将共享数据暴露出去。其实第二条就可以使用第一条来实现。我们使用一个函数来维护这个共享数据。假设该函数叫 monitor.完整的程序如下:// gopl/syn...原创 2018-08-12 21:29:48 · 660 阅读 · 0 评论 -
077-内存同步
还记得前面的银行账户存款的例子吗?为了解决竞争问题,我们曾经使用了 sync.Mutex 来保护共享变量。特别的,在读取 balance 变量的时候,我们是这样写的:func Balance() int { mu.Lock() defer mu.Unlock() return balance}当时我们说到,这里加锁需要进一步讨论。这种情况也是并发编程里让人感到...原创 2018-08-12 22:23:11 · 739 阅读 · 0 评论 -
078-只被执行一次的函数
倘若你看过我的所有文章的话,你肯定还记得曾经在学习《Linux 环境编程》的时候,也有一篇类似的文章,标题和这个一模一样——《只被执行一次的函数》。我强烈建议你回顾一下上面那篇文章。如果你没有《Linux 环境编程》的基础,强烈建议你补习一下,只会 Golang 是不行的。1. 背景相信很多同学都使用过单例模式。如果在单线程程序中,单例模式肯定没啥问题,但是如果在多线程程序中,可能...原创 2018-08-24 23:32:20 · 941 阅读 · 0 评论 -
079-竞争检测
大多数时候,我们对并发的直觉都是错误的,特别是在多核处理器上更为明显。这也是高并发程序难写的原因。人类想了种种办法来降低程序员犯错误的机率,发明了很多方法。甚至在有些语言里,干脆就不支持多线程了,比如基于 NodeJs 开发的服务器。但在 Golang 里我们无法逃避这种并发竞争。1. 竞争例子下面这个例子开启了 100 个 goroutine,读写全局变量 a.// de...原创 2018-08-25 20:26:25 · 593 阅读 · 0 评论 -
080-反射(介绍)
接触过 Java 的同学对反射的概念一定不陌生。不过这里大多数同学没接触过 Java,也不用担心。反射是一种能让程序自身去检查和操作变量的一种能力,即使不知道变量的类型也没有关系。在 C++ 里,如果你不知道一个 class 的定义,你就没有办法去调用这个 class 的任何方法,操作这个 class 的任何成员,所以说 C++ 是一种不支持反射能力的语言。这不是说 C++ 办不到这件事情...原创 2018-08-26 17:08:28 · 538 阅读 · 0 评论 -
071-并发爬虫(二)
学习从来都不是一件困难的事情。那为啥我们学习会如此痛苦?其实难在坚持。这就好比跑步并不是一件困难的事,但是难在十年如一日的坚持。如果你仔细一点,会发现我的 csdn 头像是《海贼王》这部动漫的主角头像。海贼王这部动漫从 1997 年开始连载,至今已经连载 21 年了。将一部作品连载至今,需要的不仅仅是智慧,更多的是毅力。如果我们学习也能如此,日复一日,年复一年,我想也应该能有所成就吧。...原创 2018-07-08 22:23:55 · 500 阅读 · 5 评论 -
062-一些 Go 接口设计建议
Go 语言程序设计一书作者讲了一些关于 Go 语言面向对象编程的经验和建议,如果不拿过来太可惜了。 When designing a new package, novice Go programmers often start by creating a set of interfaces and only later define the concrete types that satis...原创 2018-06-17 14:10:29 · 723 阅读 · 0 评论 -
063-Goroutine
欢迎来到新的章节—— Goroutine & Channel.如果说 goroutine 是 Golang 中的倚天剑,那 channel 就是 Golang 里的屠龙大宝刀。早在第一章,我们就展示过 cotoutine 和 channel 的魅力了,如果你忘记了,可以再次回顾一遍《goroutine 和 chan》。我不会一遍又一遍的给你介绍 goroutine 的概念,一方面是...原创 2018-06-18 19:17:32 · 438 阅读 · 0 评论 -
064-Channel
Golang 里 Channel 是一种数据类型。在 《goroutine 和 chan》 一文我们就探讨过 channel 的特性,它非常像线程安全的阻塞队列,只不过 Golang 里原生支持了它。在 Golang 里,chan 用的最多的地方就是用于 goroutine 之间的通信。很久以前你在学习多线程的时候,线程与线程之间通信的办法,一般都使用共享内存,互斥锁和条件变量这些手段,而...原创 2018-06-18 22:22:20 · 857 阅读 · 0 评论 -
065-pipeline
一个程序(函数)只干一件事,将不同的程序通过管道串联起来,完成一件复杂的事情。这是 pipeline 的核心思想。1. 介绍平时工作中,可能你会经常遇到这样的例子:$ cat abc.log | grep "INFO" | awk '{print $5}'abc.log 文件内容如下// abc.log[2018-06-05 21:30:22] [INFO] - id:4...原创 2018-06-24 00:13:42 · 609 阅读 · 0 评论 -
066-单向 channel
在 Golang 中,channel 也是一种引用数据类型。还记得我们学过哪些引用类型吗?所以 channel 作为参数,函数内对 channel 的修改,会直接影响到函数外面的变量。现在我们把上一节的 pipeline 进行改写,封装成函数的形式。1. 封装 counter 和 squarerpackage mainimport "fmt"// out 参数是传出参数fun...原创 2018-06-24 21:41:30 · 930 阅读 · 0 评论 -
067-Go 并发编程(一)
接下来了几篇文章,我们会重点讨论有关 Go 的并发编程以及常见的技术手段。当然,所有问题我们都需要从实例出发,所有的实例均来源于《The Go Programming Language》一书的第 8 章。1. 缩略图计算程序这个例子的目的很简单,给定多幅 jpg 图片,通过调用 Go 里的缩略图处理函数,生成相应的缩略图存储到本地。我们的目的不是写一个如何将图像处理成缩略图的函数,所以...原创 2018-07-01 17:55:08 · 547 阅读 · 0 评论 -
068-Go 并发编程(二)
并发编程的难点在于异常处理。今天我们继续研究缩略图的并发编程,还记得之前留下的问题吗?我们的程序没有对程序返回的错误做特殊照顾。在服务器开发领域,这样的程序的显然不够健壮。1. 让程序能够处理错误之前我们的 makeThumbnails 函数没有返回值,现在我们给它添加一个 error 类型的返回值。下面这个程序在 demo04.go 中。func makeThumbnails(f...原创 2018-07-07 16:56:51 · 363 阅读 · 0 评论 -
069-Go 并发编程(三)
相信你已经对 goroutine 已经轻车熟路了,既然如此,我们来完成一个小任务。1. 故事背景背景是这样,我们的任务分成 3 个阶段。 第一阶段:从 A 工厂采购三种不同材料。第二阶段:你需要带着三种材料,交给 B 工厂 3 个不同的车间去加工。第三阶段:等待 B 工厂所有材料加工完毕,生产出零件后,你才能带上所有零件去 C 工厂组装零件。特别的,在上面的过程中...原创 2018-07-07 18:23:13 · 378 阅读 · 0 评论 -
070-并发爬虫(一)
关于爬虫(Spider/Crawler),相信你多多少少接触过。比如你老板要你从某网站获取一批企业的黄页信息,这时候爬虫就派上用场了。而本文,我们的任务是编写一个网页抓取程序,提取网页中的 url. 我们的程序可以继续访问抓取到的 url,深度抓取更多的 url.1. 链接抓取器关于这个程序,我就不多废口舌了,你也不必过多的去研究它,掌握用法即可,我们的目的是学习并发。这个程序位于 gop...原创 2018-07-08 15:08:59 · 610 阅读 · 0 评论 -
061-类型开关(Type Switch)
这一篇仍然是与类型断言相关的,只是稍微再延伸一下。没事,不要怕,没你想象的复杂。到目前为止,关于接口我们已经掌握了它的两种使用方法:实现了同一个接口的不同具体类型都具有共性特征,而接口屏蔽了底层细节。此时我们的关注的是接口的『方法』,而不是类型。使用类型断言,我们可以判断接口值的类型。此时我们关注的是接口的『类型』和『值』,而不是方法。第二种方法通常被描述为 discrimina...原创 2018-06-17 11:57:04 · 1390 阅读 · 0 评论 -
052-方法值(Method Value)及方法表达式(Method Expression)
和这一篇相对应一篇叫函数值(Function Value). 1. 问题仍以一个简单的例子开始:package mainimport ( "fmt" "time")type Point struct { X, Y float64}func (p Point) Show() { fmt.Printf("Position{%v, %v...原创 2018-05-27 21:09:56 · 1799 阅读 · 0 评论 -
053-Bitmap (位图)
事到如今,你已经学完了 Go 的大部分语法了。尤其是这一章的 Method,相信你也可以玩的很转了。作为本章的最后压轴,我们来做一个综合练习,写一个非常经典而且强大的数据结构——Bitmap.1. bitmapbitmap 是一种非常强大的数据结构,你可以叫它 bit set,它使用比特位来存储整数。具体来说,第 N 比特位如果为 1,则表示bitmap 里存储了数字 N. 例如下面的 b...原创 2018-06-02 23:23:11 · 472 阅读 · 4 评论 -
054-接口(Interface)
历尽千辛万苦,我们越来越接近 Golang 的精髓了。从这一章开始,你需要学习 Go 语言中另一个非常重要的知识点——接口。1. 接口为何物首先,我们用几句话简单描述下接口:一种类型抽象类型一种约定...原创 2018-06-03 18:16:13 · 427 阅读 · 0 评论 -
055-实战 flag.Value 接口
如果你中间是跳跃着看的,希望你一定不要错过《参数解析》 一文。我们已经学习过参数解析的 flag 包相关使用方法,所以这里不会再赘述,如果你还不会,建议你回去学习并掌握它。1. 简单回顾很久以前,我们就学习过 flag 包的使用方法,它可以解析常见的基础类型,比如 int, string 等。 flag 包使用起来非常简单,只要使用相关的方法,将要解析的标志加入到标志集合,最后调用...原创 2018-06-03 22:14:10 · 942 阅读 · 0 评论 -
056-接口值(Interface Value)
目前为止,我们已经学过很多值类型了,比如 int 值,float 值,后面又学过函数值,方法值。到了接口这里也不例外,我们需要学习接口值(Interface value)。之所以单独拿出来讲,是因为接口值也有它与众不同的地方。1. 接口值(Interface Value)从概念上讲,接口值由两部分组成:具体类型 (Type)该类型对应的值 (Value) 之所以加一个...原创 2018-06-09 17:40:52 · 1899 阅读 · 0 评论 -
057-HTTP 服务(一)
很久以前,也就是在第一章的时候,我们就已经学过怎样使用 Go 来写一个 HTTP Server. 不过那时候我都是走马观花的过了一遍,在你不懂任何 Go 相关的语法(包括我们学过的 struct, interface 等)的情况下,你也能写出来一个 HTTP server。记得有位同学,他的同事告诉他:『为什么要把网络协议细节搞的清清楚楚,大家都是拿同样的工资,用API,会用就行』。后来我告诉...原创 2018-06-10 18:29:47 · 713 阅读 · 0 评论 -
058-HTTP 服务(二)
简单回顾一下上一篇我们做了哪些事情:学习 http.Handler 接口简单来说,Handler 是一个用于处理 HTTP 请求的『事件处理器』。type Handler interface { ServeHTTP(ResponseWriter, *Request)}自己根据 http.Request.URL.Path 实现了一个简单的路由功能。实际上,...原创 2018-06-10 23:00:18 · 498 阅读 · 0 评论 -
059- error 接口
1. error 接口一直以来,我们到处都能看到 error 作为很多函数的返回值类型出现,我们也没太关注它,一般都以下面这样的形式看到它:// err := ...if err != nil { fmt.Printf("%v\n", err)}这个 error 实际上是接口类型:type error interface { Error() string...原创 2018-06-16 22:21:17 · 423 阅读 · 0 评论 -
060-类型断言(Type Assertion)
接口相关的知识中,最重要的不仅仅是了解接口如何实现,接口的构成(类型和值)。另一个非常非常重要的知识点就是类型断言。正好上一篇文章所介绍的,根据接口判断 error 的类型,相当重要,这可以帮助我们根据不同的错误来制定相应的策略。1. 类型断言首先,类型断言,当然只能在接口上进行操作啦。普通对象你都已经知道它的类型了,还有断言的必要吗?对于接口 x,语法形式上像 x.(T) 这样的...原创 2018-06-16 23:25:26 · 1500 阅读 · 0 评论 -
051-结构体嵌入
结构体嵌入的知识(参考 《struct 结构体(三)》)我们很久前就已经学习过,不过这一次我们不是复习,而是再次深入结构体嵌入的话题。1. 复习type Point struct { X, Y float64}type Circle struct { Radius float64 Point}如果有一个 Circle 对象 c := Circle...原创 2018-05-27 20:34:51 · 479 阅读 · 0 评论 -
037-插入排序
这次来一点实战的,让你熟练掌握数组,slice. 所以选来选去,就选一个最简单的插入排序算法吧。1. 插入排序思路这个算法相信学计算机的同学都相当熟悉,不过还是先来预热一下,看看它的基本思路。 图1 插入排序 假设数组 a,大小为 8,其中 a[0...3] 都已经有序,此时我们需要将第 i 个元素(第 4 个)插入到已排序的合适的部分。最简单直接的做法就是从后向前找一...原创 2018-04-29 13:36:25 · 332 阅读 · 0 评论 -
038-Map 结构
大多数编程语言都提供了 Hash 表这种数据结构,比如 C++ 的 map/unorder_map,python 的 dict 等。hash 表是一种相当神奇且有用的数据结构,平时写代码的时候,几乎处处能遇到它的身影。在 Go 里,使用 map 这种数据结构引用底层的 hash 表。1. 声明与定义下面这四种试可以创建 map,它的 key 类型是 string,value 类型是 i...原创 2018-05-01 20:17:39 · 344 阅读 · 0 评论 -
039-struct 结构体(一)
终于迎接来 Go 语言最最核心的数据类型 —— struct. 没错,这和 C 语言里的结构体几乎一模一样。不过 Go 里的结构体,会比 C 语言的结构多一些东西,这些后面再讲。本文先简单认识一下 Go 的结构体是什么样子,以及怎么声明和定义。1. 声明与定义例1package mainimport "fmt"func main() { // 定义了一个...原创 2018-05-06 10:46:24 · 452 阅读 · 0 评论 -
040-struct 结构体(二)
现在你已经基本熟悉 struct 结构体的使用套路了。这一次,我们结合 go 语言的 package 来再来看看 struct 的使用上有什么不同。使用 package 的目的是让你定义的结构体也能被别人使用~~~比如你发明了一种很牛逼的结构体,不分享给别人岂不是很浪费?1. 项目结构和程序你要做的就是创建下面这样的文件夹 struct02,当然了名字随便你了。然后再创建一个 co...原创 2018-05-13 20:00:13 · 337 阅读 · 0 评论