强制更改Go标准库的实现

Go标准库中有一些单例的实现,比如log包中默认的Loggernet.DefaultResolver, 这些对象提供了便利的方法,但是有的时候,我们需要做一些定制话的功能,需要更改这些对象,
甚至有的时候,我们需要更改标准库的特定方法,常规手段是不起作用的, 必须使用一些"骇客"的方式。

国庆北京连绵秋雨,整好我窝在家里,实现了一个原本想12月份实现的产品,在开发项目的过程中,也遇到了一些需要更改标准库默认行为的需求,所以在这方面做了一些探索,整理出这篇文章,以飨读者。

阅读全文

Go泛型是怎么实现的?

Go 1.17中你就可以使用泛型了,可以参考我3月份的文章:Go 泛型尝鲜, 编译的时候需要加-gcflags=-G=3参数,而当前master分支,默认已经支持泛型,不需要加-G=3参数了。

你可以通过下面的步骤尝试go最新分支:

1
2
go get golang.org/dl/gotip
gotip download

编译代码的时候使用gotip替换go命令即可。

随着Go 1.17的发布,最近也涌现了很多的介绍Go泛型的文章,基本上都是简单介绍的文章。

最近Go泛型的变化是增加了两个操作符: ~|

  • an approximation element ~T restricts to all types whose underlying type is T: 代表底层类型是T
  • a union element T1 | T2 | ... restricts to any of the listed elements: 代表,类型列表之一。

这些不是我想介绍的内容,今天我肝一篇介绍Go泛型实现原理的文章,介绍Go泛型实现的方案。

对于一个函数func Echo[T any](t T){},Go编译器到底编译成了什么代码?

简单的说,当前Go泛型实现的方案和下图中的方案一样:

阅读全文

深入Go Module之未说的秘密

正常情况下,我们的go.mod依赖库的版本都是符合语义化版本 2.0.0的版本格式,或者伪版本格式。在前面的文章我没有特别提到一点的事,Go使用服务端提交的日期和commit id生成的伪版本号是符合语义化版本号2.0.0的,因为语义化版本号中规定pre-release以连接号-加一连串以逗号分隔的标识符组成,标识符以字母数字和连接号组成,所以你看到-yyyyMMddhhmmss-comitid包含两个连接号,这是正常的。

go要求依赖库要么不包含go.mod,要么依赖库中的go.mod定义的依赖库版本必须以语义化版本 2.0.0格式(或伪版本号)标志(其实更严格,除了+incompatible不能加meta字段),因为这样我们你能够明确标识某个依赖库确切的版本,这样的版本号被称之为canonical version

其实main module还可以定义non-canonical version,通过go get或者go mod tidy更新go.mod的时候,命令会尝试更新go.mod,尝试把non-canonical version转变为canonical version版本。

但是,到底有哪些non-canonical version呢?我还没看到官方文章介绍,本文尝试整理这些non-canonical version。

阅读全文

实现无限缓存的channel

Go语言的channel有两种类型,一种是无缓存的channel,一种是有缓存的buffer,这两种类型的channel大家都比较熟悉了,但是对于有缓存的channel,它的缓存长度在创建channel的时候就已经确定了,中间不能扩缩容,这导致在一些场景下使用有问题,或者说不太适合特定的场景。

阅读全文