Go 语言学习笔记(更新中...)
文章平均质量分 88
--Allen--
我知道我不知道。
展开
-
040-struct 结构体(二)
现在你已经基本熟悉 struct 结构体的使用套路了。这一次,我们结合 go 语言的 package 来再来看看 struct 的使用上有什么不同。使用 package 的目的是让你定义的结构体也能被别人使用~~~比如你发明了一种很牛逼的结构体,不分享给别人岂不是很浪费?1. 项目结构和程序你要做的就是创建下面这样的文件夹 struct02,当然了名字随便你了。然后再创建一个 co...原创 2018-05-13 20:00:13 · 336 阅读 · 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 · 1797 阅读 · 0 评论 -
055-实战 flag.Value 接口
如果你中间是跳跃着看的,希望你一定不要错过《参数解析》 一文。我们已经学习过参数解析的 flag 包相关使用方法,所以这里不会再赘述,如果你还不会,建议你回去学习并掌握它。1. 简单回顾很久以前,我们就学习过 flag 包的使用方法,它可以解析常见的基础类型,比如 int, string 等。 flag 包使用起来非常简单,只要使用相关的方法,将要解析的标志加入到标志集合,最后调用...原创 2018-06-03 22:14:10 · 941 阅读 · 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 评论 -
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 · 422 阅读 · 0 评论 -
060-类型断言(Type Assertion)
接口相关的知识中,最重要的不仅仅是了解接口如何实现,接口的构成(类型和值)。另一个非常非常重要的知识点就是类型断言。正好上一篇文章所介绍的,根据接口判断 error 的类型,相当重要,这可以帮助我们根据不同的错误来制定相应的策略。1. 类型断言首先,类型断言,当然只能在接口上进行操作啦。普通对象你都已经知道它的类型了,还有断言的必要吗?对于接口 x,语法形式上像 x.(T) 这样的...原创 2018-06-16 23:25:26 · 1499 阅读 · 0 评论 -
056-接口值(Interface Value)
目前为止,我们已经学过很多值类型了,比如 int 值,float 值,后面又学过函数值,方法值。到了接口这里也不例外,我们需要学习接口值(Interface value)。之所以单独拿出来讲,是因为接口值也有它与众不同的地方。1. 接口值(Interface Value)从概念上讲,接口值由两部分组成:具体类型 (Type)该类型对应的值 (Value) 之所以加一个...原创 2018-06-09 17:40:52 · 1896 阅读 · 0 评论 -
061-类型开关(Type Switch)
这一篇仍然是与类型断言相关的,只是稍微再延伸一下。没事,不要怕,没你想象的复杂。到目前为止,关于接口我们已经掌握了它的两种使用方法:实现了同一个接口的不同具体类型都具有共性特征,而接口屏蔽了底层细节。此时我们的关注的是接口的『方法』,而不是类型。使用类型断言,我们可以判断接口值的类型。此时我们关注的是接口的『类型』和『值』,而不是方法。第二种方法通常被描述为 discrimina...原创 2018-06-17 11:57:04 · 1390 阅读 · 0 评论 -
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 评论 -
066-单向 channel
在 Golang 中,channel 也是一种引用数据类型。还记得我们学过哪些引用类型吗?所以 channel 作为参数,函数内对 channel 的修改,会直接影响到函数外面的变量。现在我们把上一节的 pipeline 进行改写,封装成函数的形式。1. 封装 counter 和 squarerpackage mainimport "fmt"// out 参数是传出参数fun...原创 2018-06-24 21:41:30 · 929 阅读 · 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 · 477 阅读 · 0 评论 -
054-接口(Interface)
历尽千辛万苦,我们越来越接近 Golang 的精髓了。从这一章开始,你需要学习 Go 语言中另一个非常重要的知识点——接口。1. 接口为何物首先,我们用几句话简单描述下接口:一种类型抽象类型一种约定...原创 2018-06-03 18:16:13 · 426 阅读 · 0 评论 -
045-函数值(Function Value)及匿名函数(Anonymous Function)
在 Go 里,你每声明定义一个函数,就意味着产生了一个函数值。函数值就像其它类型的值一样,可以进行赋值,也可以作为函数的返回结果返回。函数值在 Go 语言里被称为 first-class value (第一等值)。相比那些什么 int 类型的值,float 类型的值来说,函数值的地位就显的要高的多,而且也重要的多。在讲解函数值前,需要普及一些基本的概念。1. 基本概念1.1 函...原创 2018-05-19 21:48:49 · 1731 阅读 · 1 评论 -
046-变长参数函数(Variadic Function)
无论是 C/C++ 还是 javascript/python,都支持变长参数函数。在 Go 里典型的变长参数就是 fmt.Printf 函数。那这种函数如何定义呢?1. 变长参数函数定义和使用变长参数函数定义如下:func name(paramname ...type) return-list即在参数名后面加上 ... 符号就行了。关于 ... 符号,在 Go 里之前已经出现过一次...原创 2018-05-19 22:44:49 · 1424 阅读 · 0 评论 -
047-Deferred 函数
想象这样一种场景:通常我们在编程的时候,经常会遇到资源申请完成后,再手工释放。比如打开一个文件后,再执行 close 操作关闭文件描述符,如果你不关闭,则会产生描述符泄露。如果程序逻辑复杂,这非常容易出错。因为你的函数可能随时遇到错误而 return 出去,此时你极易忘记 close 掉申请过的资源。Go 提供了关键字 defer 帮忙我们解决这个问题。它有点像 C++ 里的 RAII 机制,...原创 2018-05-20 14:46:03 · 431 阅读 · 0 评论 -
037-插入排序
这次来一点实战的,让你熟练掌握数组,slice. 所以选来选去,就选一个最简单的插入排序算法吧。1. 插入排序思路这个算法相信学计算机的同学都相当熟悉,不过还是先来预热一下,看看它的基本思路。 图1 插入排序 假设数组 a,大小为 8,其中 a[0...3] 都已经有序,此时我们需要将第 i 个元素(第 4 个)插入到已排序的合适的部分。最简单直接的做法就是从后向前找一...原创 2018-04-29 13:36:25 · 331 阅读 · 0 评论 -
048-panic 异常
大多数编程语言都提供了异常处理机制,恰恰相反,Go 延续了 C 语言的风格,并未提供异常处理机制。但在 Go 里,提供了 panic 异常,从某种意义上说,它也非常接近其它语言的异常处理。1. panic 异常Go 语言在编译期就能捕获大量异常,但是有些异常只会发生在运行期。典型比如运行期的除 0 错误,数组越界错误。一旦发生这种错误,程序就会引发 panic 异常导致 crash. ...原创 2018-05-20 20:25:23 · 4820 阅读 · 0 评论 -
049-方法(Method)
方法是一种特殊的函数。早在函数那一章我们就提过,函数和方法是有区别的。现在,我们可以揭开它真正的面纱了。1. 方法(method)方法,是一种和某种类型关联起来的函数,它总是依附在某个类型之上。换句话说,方法无法直接被调用,既然这样,那方法如何调用呢?1.1 从一个简单示例开始下面这个示例定义一个 Person 结构体,还有一个函数 hello,接收 Person 类型的参数,功能...原创 2018-05-20 22:20:27 · 595 阅读 · 0 评论 -
050-指针接收器(Pointer Receiver)
学会了 Method 的基本定义和使用后,我们讨论一点更加复杂的话题。1. 问题引入type Person struct { Name string Age int}// 定义 Person 的一个方法 hellofunc (p Person) hello() { fmt.Printf("Hello, my name is %s. I'm %d yea...原创 2018-05-26 10:40:13 · 1053 阅读 · 0 评论 -
053-Bitmap (位图)
事到如今,你已经学完了 Go 的大部分语法了。尤其是这一章的 Method,相信你也可以玩的很转了。作为本章的最后压轴,我们来做一个综合练习,写一个非常经典而且强大的数据结构——Bitmap.1. bitmapbitmap 是一种非常强大的数据结构,你可以叫它 bit set,它使用比特位来存储整数。具体来说,第 N 比特位如果为 1,则表示bitmap 里存储了数字 N. 例如下面的 b...原创 2018-06-02 23:23:11 · 471 阅读 · 4 评论 -
057-HTTP 服务(一)
很久以前,也就是在第一章的时候,我们就已经学过怎样使用 Go 来写一个 HTTP Server. 不过那时候我都是走马观花的过了一遍,在你不懂任何 Go 相关的语法(包括我们学过的 struct, interface 等)的情况下,你也能写出来一个 HTTP server。记得有位同学,他的同事告诉他:『为什么要把网络协议细节搞的清清楚楚,大家都是拿同样的工资,用API,会用就行』。后来我告诉...原创 2018-06-10 18:29:47 · 712 阅读 · 0 评论 -
058-HTTP 服务(二)
简单回顾一下上一篇我们做了哪些事情:学习 http.Handler 接口简单来说,Handler 是一个用于处理 HTTP 请求的『事件处理器』。type Handler interface { ServeHTTP(ResponseWriter, *Request)}自己根据 http.Request.URL.Path 实现了一个简单的路由功能。实际上,...原创 2018-06-10 23:00:18 · 497 阅读 · 0 评论 -
076-使用通信的方式共享内存
希望你还能记得住这句话: “不要使用共享数据的方式进行通信,而应该使用通信的方式来共享数据。”这一节,我们秉承这一理念,来改写前面的银行账户存款问题。1. 思路使用 channel 对控制共享数据。不要将共享数据暴露出去。其实第二条就可以使用第一条来实现。我们使用一个函数来维护这个共享数据。假设该函数叫 monitor.完整的程序如下:// gopl/syn...原创 2018-08-12 21:29:48 · 659 阅读 · 0 评论 -
077-内存同步
还记得前面的银行账户存款的例子吗?为了解决竞争问题,我们曾经使用了 sync.Mutex 来保护共享变量。特别的,在读取 balance 变量的时候,我们是这样写的:func Balance() int { mu.Lock() defer mu.Unlock() return balance}当时我们说到,这里加锁需要进一步讨论。这种情况也是并发编程里让人感到...原创 2018-08-12 22:23:11 · 739 阅读 · 0 评论 -
080-反射(介绍)
接触过 Java 的同学对反射的概念一定不陌生。不过这里大多数同学没接触过 Java,也不用担心。反射是一种能让程序自身去检查和操作变量的一种能力,即使不知道变量的类型也没有关系。在 C++ 里,如果你不知道一个 class 的定义,你就没有办法去调用这个 class 的任何方法,操作这个 class 的任何成员,所以说 C++ 是一种不支持反射能力的语言。这不是说 C++ 办不到这件事情...原创 2018-08-26 17:08:28 · 537 阅读 · 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 · 592 阅读 · 0 评论 -
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 · 1201 阅读 · 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 · 2770 阅读 · 0 评论 -
083-反射(序列化 json)
想必你已经掌握了反射的相关操作,也能够遍历结构体的字段和方法,现在我们就要进入实战了。1. 问题正如标题所指,我们的目标是能将任意类型的结构体序列化成 json. 对应的 golang 的encoding/jsong 包就是 Marshal 函数, C++ 的 jsoncpp 库来说就是 write 或 fastwrite 方法,对应到 JavaScript 就是 JSON.stringify...原创 2018-10-14 12:22:43 · 1348 阅读 · 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 · 2085 阅读 · 0 评论 -
075-互斥锁
过去我们在写 C/C++ 程序的时候,总会听到竞争的概念。比如多线程对共享变量的存取,需要加锁才能避免数据不致的问题。在 Golang 中也不例外,多个 Goroutine 存取共享变量,同样也会出现竞争问题。1. 银行转账假设 Alice 有一个银行账户。Alice 会往里存钱,她的好友 Bob 也会转钱给她。用程序来描述应该是这样:package bank// Alice...原创 2018-08-12 20:55:31 · 543 阅读 · 0 评论 -
074-Context
上一篇文章结束我留下了一下小小的悬念,说 Golang 标准库为我们提供了纯天然的取消并发请求的解决方案,在这里我就需要填坑了。1. 取消并发请求为了能让你快速上手 context,我们继续延续上一篇文章的取消并发请求的例子,使用 context 将其改写。如果你不熟悉上一篇的例子,请务必回去再看一遍。package mainimport ( "context" "...原创 2018-07-15 17:53:31 · 486 阅读 · 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 评论 -
067-Go 并发编程(一)
接下来了几篇文章,我们会重点讨论有关 Go 的并发编程以及常见的技术手段。当然,所有问题我们都需要从实例出发,所有的实例均来源于《The Go Programming Language》一书的第 8 章。1. 缩略图计算程序这个例子的目的很简单,给定多幅 jpg 图片,通过调用 Go 里的缩略图处理函数,生成相应的缩略图存储到本地。我们的目的不是写一个如何将图像处理成缩略图的函数,所以...原创 2018-07-01 17:55:08 · 547 阅读 · 0 评论 -
070-并发爬虫(一)
关于爬虫(Spider/Crawler),相信你多多少少接触过。比如你老板要你从某网站获取一批企业的黄页信息,这时候爬虫就派上用场了。而本文,我们的任务是编写一个网页抓取程序,提取网页中的 url. 我们的程序可以继续访问抓取到的 url,深度抓取更多的 url.1. 链接抓取器关于这个程序,我就不多废口舌了,你也不必过多的去研究它,掌握用法即可,我们的目的是学习并发。这个程序位于 gop...原创 2018-07-08 15:08:59 · 610 阅读 · 0 评论 -
071-并发爬虫(二)
学习从来都不是一件困难的事情。那为啥我们学习会如此痛苦?其实难在坚持。这就好比跑步并不是一件困难的事,但是难在十年如一日的坚持。如果你仔细一点,会发现我的 csdn 头像是《海贼王》这部动漫的主角头像。海贼王这部动漫从 1997 年开始连载,至今已经连载 21 年了。将一部作品连载至今,需要的不仅仅是智慧,更多的是毅力。如果我们学习也能如此,日复一日,年复一年,我想也应该能有所成就吧。...原创 2018-07-08 22:23:55 · 499 阅读 · 5 评论 -
072-火箭发射游戏(select 关键字)
不知不觉,Golang 之路已经走过了一大半。谢谢所有读者一路陪伴,也很欣慰你们能一直坚持下来。接下来,我们进入几篇比较轻松的话题,我不打算在这里全盘托出,让我们从一个火箭发射小游戏开始吧。同样,这个例子来源于《Golang 程序设计》。1. 小小发射器当然,我们并不是真的要开发一套火箭发射程序的代码,只是简单的模拟一下。这对你来说几乎就是小学生的作业。我们的目标如下:从 10 ...原创 2018-07-11 00:22:53 · 1730 阅读 · 0 评论 -
068-Go 并发编程(二)
并发编程的难点在于异常处理。今天我们继续研究缩略图的并发编程,还记得之前留下的问题吗?我们的程序没有对程序返回的错误做特殊照顾。在服务器开发领域,这样的程序的显然不够健壮。1. 让程序能够处理错误之前我们的 makeThumbnails 函数没有返回值,现在我们给它添加一个 error 类型的返回值。下面这个程序在 demo04.go 中。func makeThumbnails(f...原创 2018-07-07 16:56:51 · 363 阅读 · 0 评论