如何快速高效率地学习Go语言
要想快速高效率地掌握Go语言,关键是要通过不断写代码去训练,熟能生巧。方法是没问题的,但具体的路径呢?就像开车,能不能给个导航?我希望这篇文章能起到一个导航的作用,这里提供的路径,应该对很多人都适合。当然每个人的具体情况不同,因此路径会有差异。你可以对这个路径进行剪裁,得到最适合自己的。
目标(快速,高效率):
短时间和高效率是这里的关键词。其实只要你每天用Go来编写程序,时间一长,也就掌握了,它不需要任何技巧,大智若愚,实际上是一个不错的办法。但如果你想最快地掌握Go语言,还是需要一些技巧的。
我以前也曾经学过一段Go,大概花了2周,基本的会了,但远远没有达到掌握的程度。后来因为有其他事情就放下了。现在回想起来,当时方法不对,效果也不好。后来用我现在要讲的方法,在不到2个月的时间完全掌握了Go语言。这也得益于我以前对Java比较熟。
最终结果(掌握Go语言):
什么叫完全掌握Go语言?下面是我的标准:
- 对语言本身已掌握,可以直接在键盘上敲程序
- 给你一个项目,你大致有思路应该怎么做,知道要从那下手而且能比较顺畅地做出来。
其中#2又包括两点:
2.1. 熟悉常用的架构
2.2. 知道如何用Go语言来实现常用架构中的各个环节
其中#2.1是跟语言无关的,需要长时间的编程积累,不是短时间能完成的。#2.2是跟Go语言直接相关的,在了解语言的标准库的基础上还要熟悉常用的框架和第三方库。好消息是Go的标准库非常强大,你的主要精力要放在标准库,除此之外你只需要两三个外来库就行了。
适用人群:
这个方法只适用于已有其他语言编程经验的人,这样可以借助已有的其他语言经验,达到快速掌握Go的目的。其中2.1跟Go语言无关,主要是你以前的编程积累。你要做的是完成#1和#2.2。
高效率学习的关键是要进入一种正向反馈的自循环系统。在你掌握了基本Go语法之后,通过不断用Go写代码来加深对语言的了解和熟悉程度,之后就可以写更多、更深、更好的代码,这样就形成了正向反馈的自循环系统。像滚雪球一样,越来越大。
快速的关键是用最短的时间进入这种自循环,也就是尽快了解Go基本语法。
学习路径和导航:
学习分四个阶段。 完成之后,你应该已完全掌握Go语言。
- 了解基本语法 (时间2天-7天)
- 深入掌握Go知识点 (时间2周-5周)
- 自己动手完成一个有一定规模的项目 (时间1个月-3个月)
- 掌握Go的其他库,如“Goroutines”,“context”,“net/http”
当你完成1-3之后,你已基本掌握Go语言。#4帮你完成对整个语言的完整掌握。
以上4条给你提供了一个大致的导航,这样你就知道了要去哪,中间路径怎么走,现在到哪了,还需要多长时间才能到达。
上面的时间只是个略估,每个人的编程背景不同,每天所花的学习时间不同,最终完成时间和效果也会有不少差异。
学习内容:
了解基本语法(第一阶段):
这一阶段的目的是快速了解Go语言的基本语法(不必深入领悟细节),能自己编写简单程序(它包括安装Go),找到一个合用的IDE。最好的的教材是“Go by Example 中文”。你不必完成所有的项目,只完成前面20个就行了。很多人推荐“Go 语言之旅” 这不是个好主意。 它对一些知识点抠的太细,不利于快速进入正向自循环。“Go by Example”讲得很浅,即使你学会了实际上也并没有深入掌握知识点( 那是第二阶段的任务),但第一阶段只要知道大概就行了。正因为这样“Go by Example”才是最好的选择。
深入掌握Go知识点(第二阶段):
第二阶段的任务是掌握Go的主要知识点,大概有二三十个。 例如arrays和slices的区别,函数调用时传参还是传值(如果传值怎样改变参数的值?),指针的用法,Go中哪些类型是指针类型(Interface是指针类型吗?),Errors,Methods,package,go-sql,date 和time等等。这些看着简单,但实际上要真正掌握还是要费一些时间的。
在这一阶段,你可以通过写一些小的程序来掌握知识点。比如写一个访问数据库的程序,有增删改查功能,数据库字段包括各种类型(时间类型会复杂一点)。然后在这个基础上增加域模型,把程序分层。
关键的一点是不要拷贝别人的程序,一定要自己用键盘把程序敲出来(能敲出一个字算一个,只有实在想不出来了再去看“Go by Example”)。只有这样才能真正学到。刚开始可能会比较痛苦,但只有痛苦了,你才能学到东西,而且这是最快的方法。(当然,当你掌握了Go语言之后再拷贝别人的程序就没有问题)
比较好的状态是你每天都有问题,不断地向自己提问(然后去解决问题),问题解决了,知识点就掌握了。提不出问题怎么办?不拷贝别人的程序是一个好办法,我发现当自己用手一个字一个字地敲程序时(而不是拷贝别人的程序时)会不自觉地思考很多问题并注意到了很多以前忽略了的地方。比如说,像上面“函数调用时传参还是传值?”,你能不能自己写个程序测试一下,这样自己就能把问题回答了,而不必到网上查资料去找现成的答案。测试时,如果类型是“string”或“int“很容易,如果是map, struct呢?测试之后可能还有问题,这样再去看文章就有针对性,效果会更好。这种情况下,学习过程是完全有你来主导,是效率最高的。但需要你有比较好的编程基础。
如果你每天提的问题不多,还不足以主导整个学习过程,那你需要看书或看网上的文章来辅助。但需要注意,它只是起辅助作用,重点还是要通过写代码来领悟。每次看书的时间不要太长,太长了容易被它的思路带着走,限制了自己思维的活跃性。每次看文章只针对一个问题,充分聚焦。如果不是带着问题而只是泛泛地看书很可能当时看明白了,但第二天就又糊涂了或忘了。只有自己想明白的道理才是你自己的,书上的都是别人的知识。这样每天大概掌握1-3个知识点,天天都能感觉自己在进步,这就是最好的一种学习状态。
另外有三个技能也很重要:
-
快速查错和调试的能力
Go的错误信息还是比较清楚的,你应该可以很快发现问题在哪。关键是要找到出错的文件和行数。代码中清晰的日志输出和程序错误信息能帮你快速定位。如果你想要知道怎样打印程序错误的”stack trace“ , 那就看一下这个“Stack Traces and the Errors Package”. 如果是程序结构有问题,那么Go不会给出错误的文件名和行数, 这时就困难一点,要看你对Go运行环境的理解。 -
快速得到函数或struct的文档
好的IDE非常重要,最重要的功能是查看函数或struct的文档和跳转到某个函数。 “GoLand”是最好的IDE,但查看函数文档的和跳转的功能不好用(组合键过于复杂),不过你自己可以重新设置组合键(我设定的是点击鼠标的滑轮,因为别的方便的键都被用掉了)。“Visual Studio Code”把鼠标移过就能看函数文档,非常方便。但在我的机器上反应太慢了,只好弃用。 -
查看第三方库的源码
Go的超绝优势是当它加载第三方库时,加载的是源码而不是可执行程序。这大大加快了它的学习进度。我在学习日志库Zap时,由于它的配置参数多达十几个,我怎么也找不到完整的实例说明,试了很多组合都失败了。后来看了源码,很快就解决了问题。从这之后,碰到解决不了的第三方库的问题,我就经常会看源码,大多数时候都能把问题解决。由于在Go里看别人的源码太容易了,有时候我都没有意识到看的是别人的源码。后来再用别的语言编程时,不能很方便地查看第三方库的源码,觉得非常不方便,就想到了还是Go好。
完成项目(第三阶段):
这时你已掌握了Go语言的基本知识点,是时侯写一个真正的可以在生产环境运行的程序了。
我建议你选一个熟悉的领域,比如一个简单的电商或学生注册课程的程序。大概有两三个域模型类(struct)和数据库表。程序可以分成三层,域模型层,业务逻辑层和持久层。先不需要有用户界面。各层之间要通过接口调用, 这样你可能还要通过容器(Application Container) 产生具体类型(Concrete Type)并用依赖注入(Dependency Injection)注入到函数中。这样就有一定的复杂度了。当然这里面牵扯到不少的设计问题。 如果你暂时不想考虑太多设计问题,那你只要把程序做出来就行了,也能达到掌握Go语言的目的,不过掌握的级别不一样。 你也能写出熟练的Go程序,只是不知道如何设计而已。
如果你想把设计也包括进去, 那你要思考很多问题,例如程序的目录和包结构,设计架构和分层,编码规范,日志和错误处理,是否要支持事务。我在GitHub上完成了一个完整的程序,并且写了一些列的文章“清晰架构(Clean Architecture)的Go微服务”讲述上面的每一方面。 不过我不建议你一开始就看它。你需要自己先反复考虑这些问题,仔细设计。不需要一步到位,可以不断地对设计和程序进行重构。这中间你可能会碰到各种各样的问题,你需要在不断解决问题中成长。当你写到一定程度时,你可以去看上面提到的文章,跟你的设计和想法进行对比,印证。 如果有兴趣我们还可以讨论,共同提高。
掌握Go其他库(第四阶段):
这时你已经基本掌握了Go, 再学习其他的库就会很容易,例如“Goroutines”,context”,“net/http”。我之所以把这些放在第四阶段是因为它们不影响核心功能又有一定难度,放在最后,学习坡度会比较平缓。
学习内容的选择:
如果你只想掌握Go语言,对时间没有要求,那么内容的选择并不重要,任何学习内容和学习顺序都是有帮助的。如果你希望在最短的时间内学会,那么内容的选择和学习的先后次序就比较重要了。下面是我的一些建议,当然你可以根据自身情况量体裁衣。
知识点选择:
主要针对学习的第二阶段。不建议上来就直接使用第三方库。Go语言本身标准库非常强大,能做很多事情。使用第三方库反而会妨碍你对Go语言本身的理解。开始的时候还是聚焦于语言本身。下面是部分可选知识点:
Module
strconv
string
time
go-sql
logging
。。。
项目选择:
主要针对学习的第三阶段。我不主张一开始就选择一个gRPC或Web的项目,因为它需要你额外了解gRPC或Web,这样会分散你的注意力,你需要同时学习Go和gRPC或Web, 会加大难度。当然如果你已经对他们很熟悉就另当别论。原则是你一定要选择一个阻力最小的方向,也就是你最熟悉的项目。对多数人来讲,一个简单的访问数据库的程序应该是阻力最小的。完成这个之后,如果你愿意,可以在它的基础上加上gRPC或Web功能,如果你的架构合理,加上gRPC或Web会是一件很容易的事。
拓展库选择:
主要针对学习的第四阶段。有些人对Go“Goroutines”有误解,觉得它很容易。如果只是简单地写一个“Goroutines”确实容易,但实用的“Goroutines”都需要“Goroutines”之间通信和进行协调控制,要写出能在生产环境中可靠运行的“Goroutines”并不容易。有人专门做过调查,Go的“Goroutines”虽然比Java的“thread”要容易得多,但在程序中产生问题的概率一点也不比Java低。如果是团队项目的话,最好是在设计时就把“Goroutines”代码和其他代码分开,并由专人负责。下面是一些可以在第四阶段学习的库:
Goroutines (Channel)
net/http,
net/url
O/R mapping
reflect
文章选择:
决定那些文章要读,那些可以不读,这里主要针对Go官网上推荐的文章,在下载Go时就自带的。
需要读:
How to write Go code:
effective go:还是有帮助的,但文章太长又枯燥,建议每天只读一段,花两周时间读完,这样不会太累。
不需要读:
go faq:
关于Go语言历史和特点:可以掌握Go之后再读
时间的选择:
学习的过程同时也是遗忘的过程,只有成长的速度远远快于遗忘的速度才能一直进步。最好的方法是集中一段时间主要用来学习Go,假设每周花20小时,一个月基本小成,两个月就完全掌握了。如果每天花2个小时(一周14个小时),我估计由于遗忘的作用,可能要两个月小成,四个月才能完全掌握了。如果每天一个小时,我估计一年也学不会。写到这突然有点泄气,发现这才是问题的关键,感觉前面都有点白写了。结论是如果是业余想掌握Go确实需要比较大的毅力。
你可能要问,完全掌握了之后如果一段时间不用,难道不会忘记吗?也会忘,但那时你对Go语言本身有了深刻的理解,很短的时间就能捡起来。如果只是半生不熟的掌握,过了一段时间不用之后,就所剩不多了。