译者 | 核子可乐
编辑 | Tina
多年来,Go 社区里关于成本和收益的辩论一直非常激烈。Aliaksandr Valialkin 对 Go 新版本迭代器的批评就是其中之一。他的看法在社区里引发了大量讨论,有认同也有否定。有人认为,Go 的简洁设计注定会排除一些“可能很酷但比较高级的功能”,但显然现在迭代器让 Go 更复杂了。实际上,随着这门语言被用于其创始者未曾设想的情境中,Go 就不得不应对庞大且多样化的社区,这必然也会影响 Go 的发展方向。
众所周知,Go 语言向来以易于使用而著称。得益于其精心设计而成的语法、功能和工具,开发者可以通过 Go 轻松编写出易于阅读和维护、且复杂程度各异的应用程序。
但也有一些软件工程师抱怨 Go 语言既“无聊”又“陈旧”,理由是其缺乏其他编程语言所具备的不少高级功能,例如 monad、option 类型、LINQ、借用检查器、零成本抽象、面向方面编程、继承、函数与算子重载等。虽然这些功能有助于简化特定领域内的代码编写体验,但在好处之外,它们也对应着自己的实现成本。
具体来讲,此类功能往往会增加开发者的认知负担,而在处理生产代码时,我们最不需要的就是额外认知负担了——毕竟大家已经被业务需求搞得焦头烂额,实在不想因为这些功能令代码编写的复杂性进一步提高:
- 这些功能导致人们很难通过直接阅读代码来理解业务逻辑;
- 此类代码的调试变得更加困难,因为往往需要跨越几十个奇怪的抽象才能触及业务逻辑;
- 这些功能各有适用限制,因此向此类代码中添加新功能也变得更加困难。
这可能会大大减慢,甚至中止代码的开发进度。也正因为如此,GO 语言才决定在起步之初不引入这些功能。
遗憾的是,其中部分功能近来开始出现在 Go 新版本当中:
- 泛型已经出现在 Go 1.18 版本当中。许多软件工程师都希望能在 Go 中用上泛型,并认为这将显著提高他们在 Go 开发环境下的工作效率。但自 Go 1.18 发布以来已经过去了两年,生产率却并没有提高的迹象。Go 中泛型的总体采用率也仍然很低。为什么?因为大多数 Go 代码实际上都不需要泛型。另一方面,泛型却显著增加了 Go 语言本身的复杂性。例如,我们已经很难在引入泛型之后,正确理解 Go 类型推断的所有细节。其复杂性已经非常接近 C 类型推断。另一个问题在于,Go 中的泛型还不像 C 模板那样具备全套必要功能。例如,Go 泛型在其类型中不支持泛型方法,也不支持模板特化及模板模板参数(即模板中再套模板)等充分利用泛型编程所需要的许多其他功能。而如果把这么多缺失的功能再塞进 GO 当中,那我们得到的就是又一个过于复杂的 C 克隆。所以,当初何必费力气把泛型引入 Go 语言呢?