简化代码:泛型如何解决重复逻辑问题

写在之前
最近一段时间,工作忙碌没有太多时间用于写作。而闲暇时候,我沉湎于股市,一定程度上浪费了一些时间。在 AI 的时代,利用 AI 来学习是一种正确的方式,后续我会尽量花时间学习一些东西,并及时分享出来,希望能保持常态化的更新频率。
在 AI 时代,被 AI 影响是不可避免的,我选择拥抱、适应而不是对抗。在如今的潮流中如何保持个人的 storytelling 能力、持续进步是一个很大挑战,也是人类的挑战 —- 或许这样自身才不会退化。就目前而言,我觉得 AI 做到了很多事情,但是还是以人为本,为人服务。
替代人类或许就在不远的将来,谁知道呢🤷♂️?还是先聚焦于当下的事吧。
前言
我的工作生活中很少用到 Golang 的泛型,我想是时候一点点主动学习掌握它了。
泛型编程(Generic Programming),也称为参数化多态(Parametric Polymorphism),是一种通过编写“通用函数”来减少函数重复的编程方法。这类函数可以支持多个类型参数或参数值。
在 Go 编程语言的语境中,泛型曾是一项备受期待的特性,并最终在 Go 1.18 版本中正式加入语言核心。引入泛型的总体目标是避免样板代码(boilerplate code)和逻辑重复,使开发者能够编写可以作用于任意类型或值的函数和库。
1. 问题背景:没有泛型之前的编程方式
在泛型引入之前,像 Go 这样静态类型语言中的每一个函数,都必须明确地作用于某一种具体类型。
如果开发者希望对不同的数据类型(例如 int、int64 或 string)实现完全相同的逻辑,就不得不为每种类型分别实现一个几乎一模一样的函数。
在大型代码库中,这种做法往往会导致成千上万行重复代码,即便只是一些非常基础的工具函数,比如在数组中查找元素、或对切片进行反转等。这种实现方式明显违背了 DRY(Don’t Repeat Yourself,不要重复自己) 原则。
示例代码:没有泛型时的代码重复问题
1 | // 反转一个整数切片 |
在上述示例中,函数的核心逻辑完全一致,但由于函数签名中的类型不同,代码被迫重复实现。
在泛型出现之前,开发者通常会尝试使用接口(interface)和类型断言(type assertion)来支持多种类型,但这种方式往往显得笨重,需要手动进行类型判断,同时还牺牲了编译期类型安全性这一重要优势。
2. 引入泛型的动机
引入泛型的核心动机,在于能够将元素类型(element type)从算法和数据结构中抽离出来。这样一来,开发者可以:
一次编写,到处使用(Write once, use everywhere):
像Map、Filter、Reduce这类通用工具函数,只需编写一次,就可以作为通用包,适用于任意类型的值。类型安全的容器(Type-Safe Containers):
泛型允许创建诸如集合(Set)、树(Tree)等容器,并且在编译期就能保证类型安全,无需再依赖空接口(interface{})。减少样板代码(Reduced Boilerplate):
不再需要为每一种结构体或基础类型分别实现一套逻辑,代码体量显著缩小,也更容易维护。
3. 泛型如何解决这些问题
泛型通过引入类型参数(Type Parameters)来解决上述问题。类型参数本质上是类型的占位符,真正的类型会在函数调用时被具体化。
这些类型参数通常会受到约束(Constraints)的限制。约束本质上是一种接口类型,用来规定泛型类型必须支持哪些操作。
示例代码:使用泛型实现可复用逻辑
1 | // 一个适用于任意切片类型的泛型函数 |
在这个示例中,T 是一个类型参数,any 是它的约束,表示 T 可以代表任意类型。
Go 编译器会使用类型推断(Type Inference)机制,因此在大多数情况下,调用者甚至不需要显式地指定类型参数。
4. 何时该使用(以及不该使用)泛型
尽管泛型功能强大,但它也为语言引入了一定的复杂度。因此,Go 团队建议谨慎、克制地使用泛型。
适合使用泛型的场景:
当你需要对不同的数据类型实现完全相同的行为时,例如:- 作用于容器类型(
map、slice、channel)的通用函数 - 通用的数据结构(如集合、队列、树等)
- 作用于容器类型(
不适合使用泛型的场景:
- 你只是对某个类型参数调用方法时(此时应使用接口类型)
- 你需要针对不同的具体类型执行不同的逻辑时(应使用反射(reflection)API)
总结
泛型通过允许开发者编写可复用、已充分调试并针对多种类型优化的库,使 Go 这样的静态类型语言变得更安全、更高效、也更强大。
它将复杂性从库的使用者转移到了库的编写者身上,从而保证日常业务代码依然保持简洁、可读,同时又获得了显著的灵活性。
可以将泛型理解为一个高质量的厨房模具。
如果没有泛型,你需要为每一种材料准备一个独立、专用的模具——
比如一个专门做巧克力的、一个做果冻的、还有一个做冰块的——即便它们最终的形状都是同样的五角星。
而有了泛型,你只需要一个通用的五角星模具,无论你往里倒入的是哪种“材料”(类型),只要这种材料满足“可以被倒入并凝固”的条件(约束),这个模具就能稳定地生产出完美的五角星,而你无需重复发明工具。
更多内容
最近文章:
随机文章:
更多该系列文章,参考medium链接:
https://wesley-wei.medium.com/list/you-should-know-in-golang-e9491363cd9a
English post: https://programmerscareer.com/go-generics-01/
作者:微信公众号,Medium,LinkedIn,Twitter
发表日期:原文在 2026-01-01 10:37 时创作于 https://programmerscareer.com/zh-cn/go-generics-01/
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
评论