标签 泛型 下的文章

Go 1.25规范大扫除:移除“Core Types”,为更灵活的泛型铺路

本文永久链接 – https://tonybai.com/2025/03/27/remove-coretypes-from-go-spec

Go 1.18引入泛型无疑是Go语言发展史上的一个里程碑,它带来了类型参数、类型约束等强大的新特性。伴随这些特性,一个名为“核心类型”(Core Type)的抽象概念也被引入,旨在简化泛型初期的规范定义和编译器实现。

然而,随着社区对泛型理解的深入和实践的积累,“核心类型”带来的复杂性和局限性也逐渐显现。近日,Go团队在提案#70128中正式决定,并已在开发分支中实施:将在即将到来的Go 1.25版本(预计2025年8月发布)中,从Go语言规范中移除“核心类型”这一概念。这项看似底层的改动,实则对Go语言的简洁性、易学性以及未来发展具有深远意义。

关于Go 1.18泛型语法概念以及实现的详细说明,可以阅读我的《Go语言第一课》专栏中的“泛型篇”。

“核心类型”:泛型时代的权宜之计

在Go 1.18设计泛型时,为了快速有效地更新语言规范以适应类型参数,Go团队引入了“核心类型”。这里对当前版本Go规范中对Core Types的说明进行了截图如下:

Core Types概念的理解还是有门槛的,但结合泛型类型参数一起,简单来说就是:

  • 对于非类型参数的类型,其核心类型就是其底层类型
  • 对于类型参数,其核心类型是其类型集(Type Set)中所有类型共同拥有的**唯一*底层类型。如果类型集中类型的底层类型不唯一,则该类型参数没有核心类型。

例如,下面约束类型的核心类型是[]int:

interface{ ~[]int }

但对于下面约束类型Constraint:

type Constraint interface {
    ~[]byte | ~string
    Hash() uint64
}

由于其包含[]byte和string两种不同的底层类型,它便没有核心类型。

这种设计在当时起到了“快捷方式”的作用,许多原先依赖“底层类型”的规范规则被直接替换为依赖“核心类型”。这在一定程度上简化了泛型引入初期的工作量。

“权宜之计”带来的困扰

然而,“核心类型”作为一个抽象且有特定规则(尤其对channel、append、copy等有复杂调整)的概念,逐渐暴露出一些问题:

  1. 过度限制: 基于核心类型的规则往往比基于类型集的规则更严格。例如,根据Go 1.24的规范,对类型参数为P Constraint (上文定义的Constraint) 的变量进行切片操作 (s[i:j]) 是不允许的,因为Constraint没有核心类型,即使切片操作对[]byte和string本身都是合法的。
  2. 增加认知负担: 开发者,尤其是初学者,在理解某些非泛型代码相关的规范(如切片表达式)时,也不得不去理解“核心类型”这个泛型相关的概念,增加了学习曲线。
  3. 规则不一致感: 像索引(a[x])、len、cap等操作的规则是基于类型集设计的(检查操作对类型集中所有类型是否有效),这使得它们看起来像是语言规则中的“特例”,而基于核心类型的规则反倒成了“常态”。
  4. 阻碍未来发展: “核心类型”的存在,使得一些本可以自然推广到泛型的特性难以落地。例如,提案#48522 设想允许访问类型集中所有结构体都共享的字段 (x.f),但在核心类型的框架下显得格格不入。类似的,它也限制了更灵活的切片操作和类型推断改进的可能性。

Go 1.25的变革:回归清晰,拥抱未来

为了解决上述问题,Go 1.25选择了“移除核心类型”这条路径。具体的做法并非引入破坏性变更,而是:

  • 重写规范描述

将语言规范中所有依赖“核心类型”的地方,改用更明确、独立的语言来描述:对于涉及非泛型操作数的规则,回归到Go 1.18之前的、基于具体类型(如数组、切片、字符串、通道等)的描述方式。而对于涉及泛型操作数(类型为类型参数)的规则,添加专门的段落,清晰地阐述该操作在这种情况下需要满足的条件(通常是基于类型集的要求)。

  • 移除核心类型章节

从规范中彻底删除关于核心类型的定义和解释。

例如,内置函数close的规范描述,在Go 1.18后是:

For an argument ch with core type that is a channel…

而在 Go 1.25 中将回归到更简洁直观的形式(类似 Go 1.18 之前),并为泛型情况添加说明:

For a channel ch, the built-in function close(ch)…

If the type of the argument to close is a type parameter all types in its type set must be channels with the same element type. It is an error if any of those channels is a receive-only channel.

关键在于,这次变更旨在清理和简化规范,本身并不改变任何现有Go代码的行为,保证了100%的向后兼容性。同时,编译器输出的错误信息也将更新,不再提及令人困惑的“核心类型”,并有望在某些场景下提供更具体、指向性更强的错误提示。

对开发者的意义与未来展望

移除“核心类型”对 Go 开发者而言,短期和长期都带来了积极影响:

  • 更简洁的规范: Go 语言规范变得更加清晰、易于理解和学习,降低了心智负担。
  • 清晰的边界: 非泛型代码的行为可以独立于泛型概念来理解,逻辑更自洽。
  • 铺平道路: 这是最重要的一点。通过移除核心类型这个历史包袱和限制性框架,为未来Go语言在泛型领域引入更灵活、更强大的特性打开了大门。这包括:更灵活的泛型操作(如 #48522 提到的共享字段访问)、更强大的切片操作能力以及改进类型推断(如解决#69153 中的某些场景)。

值得注意的是,最初的讨论中曾考虑过伴随此次变更放宽一些语言规则(例如range对某些混合类型集的支持),但考虑到对现有工具链(如x/tools/ssa, vet分析器)的潜在影响以及某些场景下语义的复杂性(如range对[]byte和string的不同行为),Go团队最终决定本次Go 1.25的变更仅限于规范文本的清理和概念移除。这意味着,那些令人期待的语言灵活性提升,将作为独立的提案在未来版本中逐步引入。

小结

Go 1.25移除“核心类型”是一次重要的“技术债务”清理,它简化了语言规范,降低了开发者的学习成本,并且最关键的是,为Go 泛型的未来演进扫清了障碍。虽然它不直接改变现有代码的行为,但其长远影响值得每一位 Go 开发者关注。让我们期待一个规范更清晰、未来可能性更广阔的Go语言!

参考资料


Gopher部落知识星球在2025年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。并且,2025年将在星球首发“Go陷阱与缺陷”和“Go原理课”专栏!此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

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

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily
  • Gopher Daily Feed订阅 – https://gopherdaily.tonybai.com/feed

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

Go 1.24中值得关注的几个变化

本文永久链接 – https://tonybai.com/2025/02/16/some-changes-in-go-1-24

北京时间2025年2月12日,恰逢中国传统元宵佳节,远在美国的Go团队正式发布了Go 1.24的第一个版本Go 1.24.0。这也是Go团队在更换Tech Leader为Austin Clements后发布的首个大版本。

按照惯例,每次Go大版本发布时,我都会撰写一篇“Go 1.x中值得关注的几个变化”的文章。自2014年的Go 1.4版本起,这一系列文章已经持续了11年。

不过,随着从Go 1.17版本开始引入的“Go 1.x新特性前瞻”系列以及针对特定技术特性的专题文章,“Go 1.x中值得关注的几个变化”系列文章的形式也在不断演变。原先的“Go 1.x中值得关注的几个变化”可以理解为被目前的“Go 1.x新特性前瞻” + “特定技术特性文章” + “Go 1.x中值得关注的几个变化”所替代。

不过,随着从Go 1.17版本开始引入的“Go 1.x新特性前瞻”系列以及针对特定技术特性的专题文章,“Go 1.x中值得关注的几个变化”系列的形式也在不断演变。原先的“Go 1.x中值得关注的几个变化”已逐渐被目前的“Go 1.x新特性前瞻” + “特定技术特性文章” + “Go 1.x中值得关注的几个变化(新版)”所替代。希望各位读者能够理解这种变化,“Go 1.x中值得关注的几个变化”系列依然会延续,但文章中将不再进行细致的分析,因为这些内容已经在之前的前瞻和专题文章中讨论过了。

好了,言归正传,我们来说说Go 1.24!

1. 语言变化

正如Go一贯所做的,新版Go 1.24.0继续遵循Go1的兼容性规范。使用Go 1.24.0,你可以顺利编译和运行你用Go 1.11编写的代码。相信许多Gopher正是因为这一点而喜欢上Go,就像下面这位Gopher在Go 1.24发布后所表现出的惊喜一样:

不过,正如Go一贯所做的那样,在语法特性方面,Go显得十分“吝啬”。在Go 1.18大方地引入了泛型之后,Go团队又恢复了这种“吝啬”的风格。在Go 1.24的发布说明中,那短短的一行字充分展现了这一特点:

我们看到,Go 1.24仅仅是将Go 1.23版本中的实验特性“带有类型参数的类型别名”转正了,成为了默认特性。当然你仍然可以GOEXPERIMENT=noaliastypeparams显式关闭它。关于这个特性的具体内容,我们多次说过了,大家可以到《Go 1.24新特性前瞻:语法、编译器与运行时》温习一下它的具体内容。

不过这种“吝啬”也是很多Gopher所期望的,当年Go语言之父Rob Pike在“Simplicity is Complicated”演讲中提到的如下权威观点,影响了诸多Gopher,当然也包括我:

因此,在正在如火如荼的“spec: reduce error handling boilerplate using ?”的讨论中,就当前的情况来看,我也倾向于保持现状

2. 编译器与运行时

在2024年中旬,Fasthttp的作者、VictoriaMetrics的联合创始人Aliaksandr Valialkin曾因Go加入自定义函数迭代的特性而发文抱怨“Go正在朝着错误的方向演进”。不过他也提到,如果Go团队专注于提升Go的性能,而不是在与社区争论一些“华而不实”的语法糖,可能会赢得更多开发者的青睐:

尽管Go 1.24尚未添加对SIMD的官方支持,但引入的优化显然不会让Aliaksandr Valialkin失望。首当其冲的就是对map底层实现的优化——使用更为高效的Swiss Table。关于Swiss Table及Go 1.24重写map的思路,可以参考我的《Go map使用Swiss Table重新实现,性能最高提升近50%》一文。根据文中的实测结果,新版基于Swiss Table的map在多数测试项中表现出显著的性能提升,有些甚至接近50%!

当然,基于Swiss Table的map实现仍在不断完善,其实现者Michael Pratt将持续进行打磨和优化:

参与Go Swiss Table重写方案讨论,并提供参考实现之一的CockroachDB CTO Peter Mattis,也在X.com上分享了新map设计和实现的诞生过程与优势,大家可以阅读以加深理解。

此外,Go 1.24还优化了runtime内部的锁实现,新实现在高竞争情况下取得了显著的可扩展性提升,而不是像Go 1.24之前的实现那样随线程数增加而急剧下降。基准测试表明,在GOMAXPROCS=20时,性能提升达3倍。

更多编译器和运行时的变化,可以参考《Go 1.24新特性前瞻:语法、编译器与运行时》。

Go 1.24版本在编译器和运行时方面的优化投入和勇于改变,正是Go社区所期望的。相信后续版本在这方面的持续投入不会让Aliaksandr Valialkin失望。

3. 工具链

Go团队在Go工具链上的投入和结果一直被Go社区认可和赞扬!《Go 1.24新特性前瞻:工具链和标准库》一文中有对Go 1.24工具链变化的详细介绍,但在这里我还是要再次提及其中的三个变化。

go.mod增加tool指示符,支持对tool的依赖管理

借用《Go工具链版本已不由你定:go和toolchain指令详解》中的那幅图:

Go的目标显然是要实现对Go应用所依赖“全要素”进行版本管理”,涵盖Go版本、工具链版本、第三方包版本以及依赖工具版本的管理。而Go 1.24在go.mod中增加tool指示符就是要实现对依赖工具的版本进行管理。增加tool指示符后,你可以像管理第三方包版本那样,使用go get -tool对依赖的tool的版本进行管理,go install tool对tool进行安装,并支持一个tool同时存在多个版本在本地,这是由于通过go.mod管理的依赖的tool会被像module那样缓存在本地构建缓存中(go build cache)。

btw,再说说go 1.24对toolchain依赖管理和选择的改善。即便看了《Go工具链版本已不由你定:go和toolchain指令详解》一文,很多Gopher还是可能因为gotoolchain决策的复杂性和参与要素的众多而感到困惑,Go 1.24增加了GODEBUG=toolchaintrace=1可以输出做出决策的过程日志,告诉你Go为何会选择某个特定的toolchain版本。

go vet的增强

在Go 1.24中,go vet的功能有了较大变化,新增或增强了如下一些分析器(analyzer):

  • 新增测试分析器

可以检测test、fuzz test、基准测试和example test中的常见错误,避免因命名、签名错误或引用不存在的标识符而导致测试无法运行。

  • printf分析器增强

新增对fmt.Printf(s)的检查,如果这类调用中格式字符串并非常量且没有传入其他参数,则提醒用户使用fmt.Print。

  • buildtag分析器增强

新增对无效Go主版本构建约束的检测,避免错误引用次版本号。例如,如果你使用//go:build go1.23.1,该分析器会提醒你应该使用//go:build go1.23。

  • copylock分析器增强

增强对经典三段式for循环中包含sync.Locker的变量复制的不安全操作的诊断,防止锁的复制带来的潜在问题。这也是Go 1.23修正loopvar语义后避免Go用户误用的一个防卫手段。

新增GOCACHEPROG

另一个大家可能忽视的值得关注的改变是新增了GOCACHEPROG环境变量。

Go语言的cmd/go工具已经具备了强大的缓存支持,但其缓存机制仅限于基于文件系统的缓存。这种缓存方式在某些场景下效率不高,尤其是在CI(持续集成)环境中,用户通常需要将GOCACHE目录打包和解压缩,这往往比CI操作本身还要慢。此外,用户可能希望利用位于网络上的共享缓存(比如S3)或公司内部的P2P缓存协议来提高缓存效率,但这些功能并不适合直接集成到cmd/go工具中。

为了解决上述问题,Brad Fitzpatrick提出了一个新的环境变量GOCACHEPROG,类似于现有的GOCACHE变量。通过设置GOCACHEPROG,用户可以指定一个外部程序,该程序将作为子进程运行,并通过标准输入/输出来与cmd/go工具进行通信。cmd/go工具将通过这个接口与外部缓存程序交互,外部程序可以根据需要实现任意的缓存机制和策略。其大致结构如下:

显然一旦可以在云上存储build cache,也能缓解一下Go用户抱怨本地缓存过大的问题。当然从实际情况来看(我的本地环境),go build cache还不是最大的:

$go env|grep CACHE
GOCACHE='/Users/tonybai/Library/Caches/go-build'
GOCACHEPROG=''
GOMODCACHE='/Users/tonybai/Go/pkg/mod'
$cd /Users/tonybai/Library/Caches/go-build
$du -sh
155M    .

$cd /Users/tonybai/Go/pkg/mod
$du -sh
7.0G

我们看到在我本地的环境中,go build cache和go module cache的size相比,简直是不值得一提,所以说如果后续要有个GOMODCACHEPROG就更好了,我也十分希望能将go module cache搬移到云端(比如S3)中,甚至可以让组织内的Gopher共享这些go module cache(当然要区分不同arch和os)。

更多关于工具链的变化,可以参考《Go 1.24新特性前瞻:工具链和标准库》。

4. 标准库

Go标准库向来是变化的大户,这里我显然不会列出所有变化,甚至一些值得关注的变化,比如:json包增加对omitzero选项的支持新增weak包和weak指针等,也都在新特性前瞻或技术专题性文章中有过详细说明。

这里要说的是Go对fips 140-3合规性的支持,因为这个最终版本与当初新特性前瞻时有所变化。

基于最新的Go fips 140-3文档,我们可以得到关于fips 140-3使用方法的说明,这里简要梳理如下:

  • Go 1.24及更高版本开始,Go二进制文件可以原生运行在FIPS 140-3合规模式下,不必依赖注入boringssl等第三方C++包。
  • Go新增了的一个特殊的Go加密模块 (Go Cryptographic Module),其下有一组新增的标准库包(位于crypto/internal/fips140/…下),实现了 FIPS 140-3批准的算法。这个cryptographic module的版本当前为v1.0.0,目前正在接受CMVP认证实验室的测试。

Go引入了GOFIPS140环境变量,用于go build、go install和go test命令,以选择要链接到可执行程序中的Go加密模块版本。该环境变量有三类可选值:

  • off (默认): 使用标准库中的crypto/internal/fips140/…包。
  • latest: 类似off,但默认启用FIPS 140-3模式。
  • v1.0.0: 使用Go加密模块 v1.0.0 版本(在Go 1.24中首次发布,并在2025年初冻结),默认启用FIPS 140-3模式。

在运行时,可以通过GODEBUG=fips140=xxx来控制上述编译到Go中的Go cryptographic module是否运行在FIPS 140-3模式下,默认是off。

当使用GODEBUG=fips140=on时,Go运行时将会启用Go cryptographic module的FIPS 140-3模式。启用后,Go加密模块会执行以下操作:

  • 完整性自检: 在init阶段,会验证模块对象文件的校验和,确保代码未被篡改。
  • 已知答案自检: 根据FIPS 140-3指南,在init阶段或首次使用时,对算法进行已知答案测试。
  • 密钥一致性测试: 对生成的密钥进行配对一致性测试 (这可能导致某些密钥类型生成速度减慢,特别是临时密钥)。
  • crypto/rand.Reader改进: 使用NIST SP 800-90A DRBG,并从平台CSPRNG获取随机字节混合到输出中。
  • crypto/tls限制: 仅协商符合NIST SP 800-52r2 的协议版本、密码套件、签名算法和密钥交换机制。
  • crypto/rsa.SignPSS限制: 使用PSSSaltLengthAuto时,盐的长度会被限制为哈希的长度。

当使用GODEBUG=fips140=only时,不符合FIPS140-3的加密算法会返回错误或者panic。但是此模式仅为尽力而为,不保证符合所有的FIPS 140-3要求。

不过大家要知道的是:在Go 1.24版本中,GODEBUG=fips140=on和only在OpenBSD、Wasm、AIX和32位Windows平台上暂不受支持。

另外要想要检测FIPS 140-3模式是否已经激活,可以调用crypto/fips140.Enabled函数。

之前,一些场合用户使用BoringCrypto模块来实现某些FIPS 140-3算法的机制仍然可用,但已不被官方支持,并计划在未来版本中移除。另外要知道Go+BoringCrypto与原生FIPS 140-3模式并不兼容。这也是Microsoft Go依旧宣称将保留自己维护的符合fips140-3的Go版本的原因

5. 其他

最后重点说说WebAssembly port。

Go从Go 1.11版本开始通过js/wasm增加了对编译到Wasm的支持。Go 1.21版本又增加了对WASI的支持(GOOS=wasip1),Go 1.24版本中,Go对Wasm的支持又有了新的特性。在Go 1.24发布没多久,Cherry Mui便在官博发表了名为“Extensible Wasm Applications with Go”的介绍Go 1.24中WebAssembly新特性的文章,文章介绍了Go 1.24对Wasm的支持程度以及一些限制。这里也参考了这篇文章,简单梳理一下Cherry给出的内容要点。

Go 1.24引入了新的编译器指示符go:wasmexport,允许将Go函数导出,以便从Wasm模块外部(通常是从运行Wasm运行时的主机应用程序)调用。该指示符指示编译器将带注释的函数作为Wasm导出提供,在生成的Wasm二进制文件中可用,比如:

//go:wasmexport add
func add(a, b int32) int32 { return a + b }

这样,Wasm模块将具有一个名为add的导出函数,可以从主机调用。

这是如何实现的呢?Cherry告诉我们这是通过构建一种名为WASI Reactor的Wasm模块来实现的。WASI Reactor是一种持续运行的WebAssembly模块,可以多次调用以响应事件或请求。与在主函数完成后终止的“命令”模块不同,reactor实例在初始化后保持活动状态,其导出保持可访问状态。

在Go 1.24中,要构建一个WASI reactor需要使用下面命令:

$GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o reactor.wasm

该构建命令指示链接器不生成_start函数(wasm命令模块的入口点),而是生成_initialize函数(执行运行时和包初始化)以及任何导出的函数及其依赖项。_initialize函数必须在任何其他导出函数之前调用。而main函数不会自动调用。

go:wasmexport指示符和reactor构建模式允许通过调用基于Go的Wasm代码来扩展应用程序。这对于采用Wasm作为具有明确定义接口的插件或扩展机制的应用程序特别有价值。通过导出Go函数,应用程序可以利用Go Wasm模块提供功能,而无需重新编译整个应用程序。此外,构建为reactor可确保可以多次调用导出的函数而无需重新初始化,使其适用于长时间运行的应用程序或服务。

次卧,Go 1.24还放宽了对可用于go:wasmimport函数的输入和结果参数类型的限制。例如,可以传递bool、string、指向int32的指针或指向嵌入structs.HostLayout并包含受支持字段类型的结构体的指针,这使得Go Wasm应用程序可以用更自然的方式编写,并消除了不必要的类型转换。

不过,go:wasmexport当前也有局限性,首先,Wasm 是单线程架构,没有并行性。go:wasmexport标识的函数可以生成新的goroutine。但是,如果函数创建了后台goroutine,则当go:wasmexport指示的函数返回时,它将不会继续执行,直到回调到基于Go的Wasm模块。

另外,尽管Go 1.24中放宽了一些类型限制,但对于可与go:wasmimport和go:wasmexport函数一起使用的类型仍然存在限制。比如由于客户端的64位体系结构和主机的32位体系结构之间的不匹配,我们无法传递内存中的指针。例如,go:wasmimport指示的函数不能采用指向包含指针类型字段的结构体的指针。

但不可否认的是go:wasmexport的支持,让Go更稳固了自己成为主流wasm开发语言之一的位置,虽然还有各种不足。近期Docker之父的初创公司Dagger就发博客宣称使用了Go+WebAssembly重写了其Dagger Cloud的前端

6. 小结

Go 1.24的发布,标志着Go语言在保持其核心理念——简洁与兼容性的同时,进入了一个新的发展阶段。这个版本没有在语法上大刀阔斧,而是将重心放在了底层性能优化、工具链完善和新兴技术布局上,展现出Go团队务实且具有前瞻性的发展策略。同时,Go 1.24也可以看成是一个承上启下的版本。它既巩固了Go语言在性能和工具链方面的优势,又为未来的发展方向做出了积极的布局。Go语言正以稳健的步伐,朝着更高效、更安全、更具适应性的方向迈进。我们可以期待,在未来的版本中,Go将继续在云原生计算、WebAssembly、AI应用等领域发挥更大的作用,为开发者带来更多的惊喜。

借此文章插播一条国内Go社区的news!

近期GoCN社区发文“Farewell Go,Hello AI:是时候说再见了”和所有国内Go开发人员分享了“GoCN社区将正式转型升级为ThinkInAI社区”,全面拥抱AI的决定!这也意味国内最大Go技术社区的退出,最大Go技术大会GopherChina的正式落幕!除了AI是热门赛道这一原因之外,文章也给出了Go技术分享遇到瓶颈的说法:

不过就像文中所说的“这是任何技术发展到成熟阶段的必然现象”,在评论中一些Gopher也提到:一个技术不再被更多讨论是成熟的标志

这其实与我在《2024年Go语言盘点:排名历史新高,团队新老传承》一文中表达的Go演进趋势不谋而合!Go真的进入了成熟期了!

GoCn不在了,但go在国内的传播和使用依然会继续。请继续关注诸如Gopher Daily、我的公众号以及国内其他诸如像鸟窝老师的blog以及公众号,了解Go的最新动态以及技术理解。

最后感谢AstaXie(谢孟军)对国内Go社区发展所做出的卓越贡献,我也因有幸多次参与GopherChina以及会上分享而感到无比自豪。


Gopher部落知识星球在2025年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。并且,2025年将在星球首发“Go陷阱与缺陷”和“Go原理课”专栏!此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

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

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily
  • Gopher Daily Feed订阅 – https://gopherdaily.tonybai.com/feed

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

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 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