Go 泛型用了一年,说说真实感受
Go 1.18 出泛型的时候,团队讨论过要不要用,当时的结论是观望。去年初我们把最低版本升到 1.21 之后,终于把泛型放进了代码规范,允许使用。一年下来,谈谈真实感受。 泛型真正帮到我们的地方,比想象中窄。 一年下来高频使用的场景其实就三类: 容器类工具函数。Map、Filter、Contains 这些,以前用 interface{} + 反射写,又慢又不安全,现在干净多了。 类型安全的并发原语。我们自己封了个 sync.Map 的泛型包装,key 和 value 的类型在编译期就确定,用起来踏实。 数据访问层的通用分页查询,一个 func Query[T any](...) 替掉了以前代码生成器吐出来的几十行重复代码。 但有些地方我们明确禁止用泛型: 业务结构体不搞泛型。 Service[T]、Repo[T] 这种"框架感"的东西一旦放出来,业务代码的可读性会断崖式下跌。领域模型就该是具体的,UserRepo 比 Repo[User] 好读得多。 能用接口解决的不要用泛型。 泛型和接口最大的区别是:接口是运行时多态,泛型是编译期展开。大部分业务场景需要的是前者。 一个观察:团队里泛型使用量最大的,是以前用 interface{} 最多的那批代码。这说明泛型在 Go 里解决的主要不是"表达力"问题,而是"以前只能靠反射硬扛"的那部分代码的类型安全问题。从这个角度看,泛型是改良,不是革命。 最后记录一个实用主义的心得:升级到 1.21 之后 min/max 内置函数直接删掉了我们自己写的工具函数,这种小快乐积累起来,也是升级的意义。