2020年Go语言盘点:新冠大流行阻挡不了Go演进的步伐

img{512x368}

2020,这一六十年一遇的庚子年的确“名不虚传”。在这一年发生了很多事,而最受瞩目的事情莫过于新冠疫情的全球大流行。疫情给全球的经济带来了近似毁灭性的打击,给人们的生命带来了极大威胁,给人们的生活也带来了很大痛苦及不确定性。好在这个糟糕的2020年马上就要过去了!相信此时此刻每个人心中都会有一句呐喊:“2020,快滚吧!”。

然而肆虐的新冠疫情并没有阻挡住Go语言前进的坚实步伐。在这艰难的一年中,在Go核心开发团队和Go社区的齐心协力下,Go同样取得了不俗的成绩,甚至在2020年3月(那时Go 1.14版本刚刚发布不到一个月),Go在TIOBE的编程语言排行榜中还一度挤进前十(而2019年同期,Go仅位列18位):

img{512x368}

这恰说明Go语言的开发与推广工作得到了更多来自全球的开发者的认可。在这篇文章中,我们就来做一下2020年Go语言的盘点,看看在2020年围绕Go语言、Go社区和Go生态圈都发生了哪些有影响和有意义的事情。

1. 面对大流行,Go核心团队给出“定心丸”

大流行始于2020年1月的武汉,但真正的全球大流行则大致始于2020年3月。面对新冠全球大流行,Go核心开发团队于3月25日作出反应,在官博发表文章《Go, the Go Community, and the Pandemic》,迅速调整了Go语言2020年的演进计划,给出了大流行期间的工作原则:

  • Go始终排在诸如个人和家庭健康与安全之类的基本问题之后;
  • 调整全年Go技术会议的计划,推迟或改为线上举办虚拟技术大会,为全球Gopher提供获取这些会议最新信息的渠道服务;
  • 为在线培训师、Go职位发布提供便利服务;
  • 为新冠病毒提供帮助工作台:https://covid-oss-help.org/;
  • 调整Go工作计划,缩减Go 1.15中包含的新特性和改进,但会遵循Go 1.15的发布时间表;重点支持gopls、pkg.go.dev的演进和优化。

Go核心开发团队的这份声明虽然简短,但却给Go社区吃了一颗“定心丸”,为Go语言在2020新冠大流行年中的稳步演进确定了节奏,指明了方向,奠定了基础。

2. Go在2020年值得关注的那些变化

2020一年,Go核心开发团队、社区和生态圈做了很多工作,但这里无法一一枚举,仅挑出一些重要的变化列在这里:

  • 2020年2月26日,Go 1.14版本发布。主要的变动点包括:

    • 嵌入接口的方法集可重叠;
    • 基于系统信号机制实现了异步抢占式的goroutine调度;
    • defer性能得以继续优化,理论上有30%的性能提升;
    • go module已经生产就绪,并支持subversion源码仓库;
    • 重新实现了运行时的timer;
    • testing包的T和B类型都增加了自己的Cleanup方法。
  • 2020年4月20日,发布2019年Go开发者调查结果

    • 参与2019开发者调查的gopher数量几乎为2018年的2倍,达到10,975人;
    • 大多数受访者每天都在使用Go,而且这个数字每年都有上升的趋势;
    • Go的使用仍然集中在科技公司,但Go越来越多地出现在更广泛的行业中,如金融和媒体;
    • 调查的大部分指标的同比值都很稳定;
    • 受访者正在使用Go来解决类似的问题,特别是构建API/RPC服务和CLI,和他们工作的组织规模大小关系不大;
    • 大多数团队试图快速更新到最新的Go版本;当第三方供应商迟迟不支持当前的Go版本时,就会给开发者造成采用障碍;
    • 现在Go生态系统中几乎所有人都在使用go module,但围绕包管理的一些混乱仍然存在;
    • 需要改进的高优先级领域包括调试、go module使用以及与云服务交互的体验改善;
    • VS Code和GoLand的使用量持续增加;现在每4个受访者中就有3个首选它们。
  • 2020年6月,vscode-go扩展(vscode上的go标准插件)将主代码库从github.com/microsoft/vscode-go迁移到github.com/golang/vscode-go,成为Go官方项目的一部分。

  • 同在2020年6月,pkg.go.dev网站开源!该网站是Go团队在Go社区建设方面做出的主要工作,开源后的pkg.go.dev将接收更多来自社区的想法和改进意见,比如:11月,pkg.go.dev就发布了新版页面设计原godoc.org的请求也被重定向到pkg.go.dev(广大gopher可能需要一段时间来适应这种改变)。

  • 2020年8月,Go 1.15版本发布,其主要的变动点包括:

    • GOPROXY新增以管道符为分隔符的代理列表值;
    • module cache的存储路径可设置;
    • 改善派生自原生类型的自定义类型变量在panic时的输出形式;
    • 将小整数([0,255])转换为interface类型值时将不会额外分配内存;
    • 加入更现代化的链接器(linker),新链接器的性能要提高20%,内存占用减少30%;
    • 增加tzdata包。
  • 2020年11月初,全球最具影响力的Go语言技术大会GopherCon 2020在线上举行!Austin Clements详细讲解了Go 1.14加入的基于系统信号的抢占式调度器;Go语言之父之一的Robert Griesemer讲解了Go泛型当前的状态以及未来的计划。会后Russ Cox确认了Go团队将在Go 1.18版本中加入Go泛型(类型参数)作为试验特性;

  • 2020年11月10日,Russ Cox代表Go核心开发团队发文庆祝Go语言发布11周年,在文中他回顾了Go这一年来的收获以及对2021年Go 1.16和Go 1.17的展望。文中他还提到了GOPATH的历史使命即将结束,Go将开启全面module-aware模式的Go工具链时代!(下图来自推特):

img{512x368}

  • 2020年12月中旬,Go 1.16beta1发布。在Go 1.16中,Go将原生提供对Apple M1芯片(darwin/arm64)的支持;同时,在Go 1.16中go module将成为默认包依赖管理机制;Go 1.16还提供了支持在Go二进制文件中嵌入静态文件的官方原生方案,支持对init函数的执行时间和内存消耗的跟踪,链接器性能得到进一步优化等。

  • 2020年12月16日,gopls v0.6.0发布。同期,vscode-go也正计划将gopls作为默认语言服务器

3. Go语言当前的状态:已来到“稳定爬升的光明期”

今年笔者在知乎上滞留的时间比往年要长一些,看到很多人问与Go相关的一些问题,大致都是询问有关Go语言前景的,比如:

无论上述问题的题目有何不同,其本质的疑问都是“Go语言前景/钱景如何,值不值得投入去学习?”。那么是否存在一种成熟的方法能相对客观地描会出Go语言的发展态势并能对未来Go的走势做出指导呢?我想Gartner的技术成熟度曲线(The Hype Cycle)或许可以一试。

我们知道Gartner的技术成熟度曲线又叫技术循环曲线,是企业用来评估新科技是否要采用或采用时机的一种可视化方法,它利用时间轴与该技术在市面上的可见度(媒体曝光度)决定要不要采用以及何时该种新科技,下面就是一条典型的技术成熟度曲线的形状:

img{512x368}

同理,将该技术成熟度曲线应用于某种编程语言,比如Go,我们就可以用它来判断该编程语言所处的成熟阶段以辅助决定要不要采用以及何时采用该门语言。我们从知名的TIOBE编程语言指数排行榜获取Go从2009年开源以来至今的指数曲线图,并且根据Go版本发布史在图中标记出了各个时段的Go发布版本:

img{512x368}

对比上面的Gartner成熟度曲线,相信你肯定有所发现。我们共同来解释一下:

  • Go语言从2009年宣布开源以来,经历了两次“高峰”:一次是2009年刚刚宣布开源后,一次是在Go1.7~Go 1.9期间。显然,第一次的高峰实际上是一个“假高峰”,那时的Go连1.0版本都尚未发布,我们完全可以将其“剔除”掉。
  • 从图中来看,Go语言的技术萌芽期是比较长的,从2012年的Go 1.0一直持续到2015年的Go 1.5
  • Go 1.5版本的自举以及Go垃圾回收延迟的大幅下降“引爆”了Go的“媒体曝光度”,Go技术的“期望膨胀期”开始,经历从Go 1.6Go 1.9版本的发布后,业界对Go的期望达到了峰值;
  • 从Go 1.10开始,Go似乎变得“仿徨”起来,原本期望Go“一统天下”的愿望没能实现,全面出击失败后,期望的落空导致了人们对Go产生了“功能孱弱劣势”的印象,于是Go在Go 1.11发布前跌到了“泡沫破裂”的谷底;
  • Go 1.11引入了Go module,给社区解决Go包依赖问题打了一剂强心剂,于是Go又开始了缓慢的爬升;
  • 从TIOBE提供的曲线来看,Go 1.12Go 1.15版本的发布让我们有信心认为Go已经进入了“稳步爬升的光明期”。

到此,我相信知乎上的很多问题都应该迎刃而解了,剩下的只是如何学习Go的细节如何Go进阶了。

不过可能还有很多朋友会问,Go何时能达到实质生产高峰期呢?这个问题真不好回答。但进入了“稳步爬升的光明期”后的Go到达实质生产高峰期只是一个时间问题了,也许2022年初发布的支持Go泛型特性的Go 1.18版本会快速推动Go向更高阶段进发!

4. 展望Go的2021:继续蓄力,迎接下一个“引爆点”

促使Go回到“稳步爬升光明期”的go module机制将在2021年年初正式发布的Go 1.16中成为默认包依赖管理机制。而Go 1.16版本也已经处于特性冻结并发布了beta1版本的阶段,其更多特性可以参考我的“Go 1.16新功能特性不完全前瞻”一文。

将于2021年八月发布的Go 1.17的里程碑已经建立, 从里程碑的内容来看,已基本确定加入的功能特性和改进包括:

当然Go 1.17还会持续优化链接器,更多功能特性和改进还待Go团队策划补充。

而万众期待的Go泛型依然会继续打磨,从2016年Ian Lance Taylor提出“Go should have generics”的设计草案以来,Go泛型草案至今已经讨论了4年多了,这再次证明了Go团队对于这类会显著增加Go复杂性的特性是多么地“慎之又慎”。虽然Go团队初步确定了在Go 1.18版本中将Go泛型(类型参数)落地,但近期Go项目中关于Go泛型的主issue:proposal: spec: generic programming facilities中仍然有不少反对的声音。Go团队在“继续保持Go简单”的道路上真是任重道远啊!

总之,2021年,Go将继续稳步爬升,也许爬的并没有那么快,但在我看来,这是在积蓄力量,等待着下一个引爆点。

5. 小结

Go在新冠疫情大流行的历史时期依旧步行稳健,为下一个“引爆点”积极蓄力。Go在自己传统领域依旧存在明显优势,比如:企业级应用、基础设施、中间件、微服务API、命令行应用等,并且在这些领域取得了越来越多开发者的青睐。

Go在其他领域也有“意外收获”,比如:在黑客工具领域,Go已经逐渐威胁着Python的龙头地位了,显然语法简单原生并发自带“电池”、轻松跨平台的编译以及编译为独立二进制文件的Go与黑客的需求十分契合。不过,在安全领域成为了进攻“武器”,这想必是Go设计者们所意料不到的。

6. 福利!2020年本博客最受欢迎Go相关文章TOP10


Gopher部落知识星球已正式转正了!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!星球首开,福利自然是少不了的!2020年年底之前,8.8折加入星球,下方图片扫起来吧,先到先得哦!

Go技术专栏“改善Go语⾔编程质量的50个有效实践”正在慕课网火热热销中!本专栏主要满足广大gopher关于Go语言进阶的需求,围绕如何写出地道且高质量Go代码给出50条有效实践建议,上线后收到一致好评!欢迎大家订阅!

我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网热卖中,欢迎小伙伴们订阅学习!

img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如何作废一个已发布的Go module版本,我来告诉你!

img{512x368}

Go语言自诞生以来,一路走到今天已经经历了11个年头了。其包依赖管理机制也从无到有,从vendor演化成了如今的Go module。Go module从Go 1.11进入gopher们视野,到目前的Go 1.15,其改进和优化一直在持续。在即将到来的Go 1.16中,Go module将成为默认包依赖管理模式(即默认GO111MODULE=on)。但即便如此,我们在进行go module的实践过程中依然还会遇到一些“棘手”的问题,本文就将针对一个Go module实践中的具体问题做深入描述,并告诉你目前可用的最佳解决方案(也许在go module的后续演进过程中可能会有更好的解决方案或干脆消除掉这个机制上的问题)。

1. 一不小心将一个处于broken状态的module发布了出去

人总是会犯错的,作为Go包/module的作者,我们偶尔也会出现这样的低级错误:将一个处于broken状态的module发布了出去。比如:bitbucket.org/bigwhite/m1是我维护的一个module(专为此文创建的公共go module),它目前已经进化到v1.0.1版本了:

// bitbucket.org/bigwhite/m1/main.go

package m1

import "fmt"

func M1() {
    fmt.Println("This is m1.M1 - v1.0.1")
}

m1这个module有两个消费者:c1和c2,它们依赖的也都是m1的v1.0.1版本:

// c1的go.mod
module github.com/bigwhite/c1

go 1.14

require bitbucket.org/bigwhite/m1 v1.0.1

// c1的main.go
package main

import (
    "fmt"

    "bitbucket.org/bigwhite/m1"
)

func main() {
    fmt.Println("This is c1")
    m1.M1()
}

// c2的go.mod
module github.com/bigwhite/c2

go 1.14

require bitbucket.org/bigwhite/m1 v1.0.1

// c2的main.go

package main

import (
    "fmt"

    "bitbucket.org/bigwhite/m1"
)

func main() {
    fmt.Println("This is c2")
    m1.M1()
}

c1和c2所在的Go开发环境均使用下面的GOPROXY设置:

export GOPROXY=https://goproxy.cn,direct

我们用一幅示意图来描述当前的状态:

img{512x368}

以c1为例,构建并运行c1:

// c1的module root目录下
$go build
go: finding module for package bitbucket.org/bigwhite/m1
go: downloading bitbucket.org/bigwhite/m1 v1.0.1
go: found bitbucket.org/bigwhite/m1 in bitbucket.org/bigwhite/m1 v1.0.1

$./c1
This is c1
This is m1.M1 - v1.0.1

接下来,作为m1的作者,我犯了一个低级错误:将更新了的但却无法编译成功的m1打标签为v1.0.2发布了出去:

// bitbucket.org/bigwhite/m1的m1.go
package m1

import "fmt"

func M1() {
    var a int // 编译器错误:a declared but not used
    fmt.Println("This is m1.M1 - v1.0.2")
}

// 在m1的module root目录下
$git commit -m"update m1 to v1.0.2(broken)" .
[master af1dd21] update m1 to v1.0.2(broken)
 1 file changed, 2 insertions(+), 1 deletion(-)
$git tag -m"tag v1.0.2(broken)" v1.0.2
$git push --tag origin master
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 492 bytes | 492.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
cTo https://bitbucket.org/bigwhite/m1.git
   911bbc5..af1dd21  master -> master
 * [new tag]         v1.0.2 -> v1.0.2

就这样,我一不小心将一个处于broken状态的module版本m1@v1.0.2发布了出去!此时此刻,m1的v1.0.2版本还仅存在于其源仓库站点上,即bitbucket/bigwhite/m1中,在任何一个GoProxy服务器上还尚无该版本的缓存

2. 发布处于broken状态的module对“消费者”的影响

依赖m1的两个项目c1和c2此时依赖的仍然是m1@v1.0.1版本,如未显式升级对m1的依赖,c1和c2的构建不会受到处于broken状态的module v1.0.2版本的影响。

并且此时此刻,由于m1@v1.0.2尚未被GoProxy服务器所缓存,在GOPROXY开启的情况下,go list是查不到m1有可升级的版本的:

// 以c2为例:
$go list -m -u all
github.com/bigwhite/c2
bitbucket.org/bigwhite/m1 v1.0.1

但如若绕开GOPROXY,那么go list则可以查找到m1的最新版本为v1.0.2(我们通过设置GONOPROXY来使得go list查询m1的源仓库而不是代理服务器上的缓存):

$GONOPROXY="bitbucket.org/bigwhite/m1" go list -m -u all
github.com/bigwhite/c2
bitbucket.org/bigwhite/m1 v1.0.1 [v1.0.2]

此时,如若某个m1的消费者在GOPROXY开启的情况下显式更新对m1版本的依赖,以c2如此操作为例:

$ go get bitbucket.org/bigwhite/m1@v1.0.2
go: downloading bitbucket.org/bigwhite/m1 v1.0.2
# bitbucket.org/bigwhite/m1
/root/go/pkg/mod/bitbucket.org/bigwhite/m1@v1.0.2/m1.go:6:6: a declared but not used

c2对m1依赖版本的显式更新,触发了GOPROXY对m1@v1.0.2版本的缓存,上述操作后,当前的状态如下示意图:

img{512x368}

这之后,其他m1的消费者,比如c1,便能够在GOPROXY开启的情况下查询到m1存在新版本v1.0.2,即使它是broken的:

// 以c1为例:
$go list -m -u all
github.com/bigwhite/c1
bitbucket.org/bigwhite/m1 v1.0.1 [v1.0.2]

一旦broken的m1版本(v1.0.2)进入到Proxy的缓存,那么其“危害性”便“大肆传播”开了。此时module m1的新消费者都将受到影响!比如这里我们引入一个新的消费者c3(同样设置GOPROXY为goproxy.cn):

// c3的main.go
package main

import (
    "fmt"

    "bitbucket.org/bigwhite/m1"
)

func main() {
    fmt.Println("This is c3")
    m1.M1()
}

c3的首次构建就会报错:

// c3下:
$go build
go: finding module for package bitbucket.org/bigwhite/m1
go: found bitbucket.org/bigwhite/m1 in bitbucket.org/bigwhite/m1 v1.0.2
# bitbucket.org/bigwhite/m1
/root/go/pkg/mod/bitbucket.org/bigwhite/m1@v1.0.2/m1.go:6:6: a declared but not used

下面是当前问题的最新状态图:

img{512x368}

3. 如何作废掉已发布的那个module版本

如果在GOPATH时代,废掉一个之前发的包版本是分分钟的事情,因为那时包消费者依赖的都是latest commit。包作者只要fix掉问题、提交并重新发布即可。

但是在go module时代,作废掉一个已经发布了的go module版本,还真不是一件能轻易做好的事情。这很大程度是源于大量Go module代理服务器的存在。下面我们来看看可能的问题解决方法:

1) 重新发布broken的module版本

要解决上述问题,Go包作者们的一个很直接的解决方法是:重新发布broken的module版本。但这样做真的能生效么?

如果所有m1的消费者都通过m1所在代码托管服务器(bitbucket)获取m1的特定版本,那么这种方法还真能解决掉这个问题。m1的作者仅需删除掉远程的tag: v1.0.2,在本地fix掉问题,然后重新tag v1.0.2并push发布到bitbucket上的仓库中即可。这样,对于已经get到broken v1.0.2的消费者来说,只需清除掉本地的module cache(go clean -modcache),再重新构建即可;对于m1的新消费者,直接得到的就是重新发布后的v1.0.2版本。

但现实的情况时,Go在1.13版本中就将GOPROXY的默认值设置为https://proxy.golang.org,direct了,国内我们通常使用七牛云的代理:goproxy.cn。因此,一旦一个module版本被发布,当某个消费者通过其配置的goproxy获取该版本时,该版本就会在短时间内被缓存在对应的代理服务器上。后续通过该goproxy服务器获取那个版本的m1时,请求不会再回到m1所在的源代码托管服务器,这样即便m1的源服务器上的v1.0.2版本得到了重新发布,那么散布在各个goproxy服务器上的broken v1.0.2依旧存在,并且被“传播”到各个m1消费者的开发环境中,而重新发布后的v1.0.2版本却得不到“传播”的机会:

img{512x368}

因此,从消费者的角度看,m1的v1.0.2版本依旧是一个broken的版本,m1作者的解决措施无效

很多人问,即便m1的作者删除了v1.0.2这个发布版本,各大goproxy服务器上的broken v1.0.2版本是否也会被删除呢?遗憾的告诉你:不会。

Goproxy服务器当初的一个设计目标就是尽可能的缓存更多包/module。即便某个module的源码仓库都被删除了,这个module的各个版本依旧缓存在goproxy服务器上,这个module的消费者依然可以正常获取该module并顺利构建。因此,goproxy服务器当前的实现都没有主动删掉某个module缓存的特性。

2) 发布module的新patch版本

面对上述问题,Go社区当前的最佳实践就是发布module的新patch版本。以上面m1为例,我们废除掉v1.0.2,在本地修正问题后,直接打v1.0.3标签,并发布push到远程代码服务器上。这样整体状态就变成了下面示意图中样子了:

img{512x368}

  • 对于依赖m1@v1.0.1版本的c1,在未手工更新依赖版本的情况下,它仍然可以保持成功的构建;
  • 对于m1的新消费者,比如c4,它首次构建时使用的就是m1的最新patch版v1.0.3,成功跨过了作废的v1.0.2并成功完成构建;
  • 对于之前曾依赖v1.0.2版本的消费者c2来说,此时需要手工介入才能解决问题。我们在c2环境手工升级依赖版本到v1.0.3,这样c2也会得到成功构建。

4. Go 1.16增加retract指示符用于标识作废的module版本

上述的发布module的新patch版本的解决方法其实仍存在两个问题:

  • 消费者如何发现m1发布了v1.0.3?
  • 消费者如何知晓m1的作者将v1.0.2版本作废掉了?

根据前面的描述,如果尚无消费者手工下载v1.0.3,那么proxy server上不会有v1.0.3版本的缓存,在本地通过go list -u -m all 也查不到v1.0.3的存在,除非是在设置GONOPROXY=bitbucket.org/bigwhite/m1前提下的go list查询。

另外在go 1.15及以前版本中,Go原生并没有提供标识某个版本作废的机制,在Go 1.16中,module的作者可以在自己module的go.mod中使用retract指示符标识出哪些版本为作废的,不推荐使用的。语法形式如下:

// go.mod
retract v1.0.0           // single version
retract [v1.1.0, v1.2.0] // closed interval

我们还用m1为例,我们将m1的go.mod更新为如下内容:

//m1的go.mod
module bitbucket.org/bigwhite/m1

go 1.16

retract v1.0.2

将其放入v1.0.3标签中并发布!现在m1的消费者c2要查看m1是否有最新版本时,可以查看到以下内容(c2本地环境使用go1.16版本):

$GONOPROXY=bitbucket.org/bigwhite/m1 go list -m -u all
github.com/bigwhite/c5
bitbucket.org/bigwhite/m1 v1.0.2 (retracted) [v1.0.3]

从go list的输出结果中,我们看到了v1.0.2版本上有了retracted的提示,提示该版本已经被m1的作者作废了,不应该再使用,应升级为v1.0.3。但retracted仅仅是一个提示作用,并不影响go build的结果,c2环境(之前在go.mod中依赖m1的v1.0.2)下的go build不会自动绕过v1.0.2,除非显式更新到v1.0.3。


“Gopher部落”知识星球开球了!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!星球首开,福利自然是少不了的!2020年年底之前,8.8折(很吉利吧^_^)加入星球,下方图片扫起来吧!

Go技术专栏“改善Go语⾔编程质量的50个有效实践”正在慕课网火热热销中!本专栏主要满足广大gopher关于Go语言进阶的需求,围绕如何写出地道且高质量Go代码给出50条有效实践建议,上线后收到一致好评!78元简直就是白菜价,简直就是白piao! 欢迎大家订阅!

我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网热卖中,欢迎小伙伴们订阅学习!

img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats