当前位置: 首页 > news >正文

为什么 Rust 能不断进化,而 C++ 和 Go 却越来越“保守”?

文章目录

  • 为什么 Rust 能不断进化,而 C++ 和 Go 却越来越“保守”?
    • 从 Python2 到 Python3 的历史教训
    • C++ 背着历史包袱前进
    • Go 过度保守的演进
    • Edition 机制让 Rust 不断进化
    • 结语

为什么 Rust 能不断进化,而 C++ 和 Go 却越来越“保守”?

任何一门想长久发展的编程语言都面临着一个问题:如何在兼容旧代码的前提下,让语言持续进化。

从 Python2 到 Python3 的历史教训

从 Python2 到 Python3,是编程语言如何演进这个话题里,一个永远绕不开的经典反面案例。

Python 早期为了易用性做了很多妥协,随着语言的持续演进,问题越来越明显,这使得开发者痛苦不堪。

而在这一大背景,Python3 以不兼容 Python2 的方式在 2008 年发布。这既无奈,但又必须这么做。

而这一决定,使得整个 Python 社区产生了巨大的分裂,继续留在 Python2 意味着项目稳定、依赖齐全和生产可用。升级到 Python3 意味着未来方向、语言更加合理。

那时,在社区找开源包要专门看支持 Python2 还是 Python3;招聘要求 JD 上要专门写会 Python2 还是 Python3。因为从本质上来说, Python2 和 Python3 就是两门不同的编程语言。

这是一个极其尴尬的局面,而这场分裂到最后统一生态持续了十二年,从 2008 年 Python3 的发布到 2020 年 Python2 正式停止维护。最终,这笔账由整个社区来承担。

C++ 背着历史包袱前进

C++ 的最大特点是永远不会轻易破坏兼容性。从 1985 年诞生至今,很多几十年前的代码在今天依然能编译。这听起来很美好,但是代价是巨大的。

因为 C++ 只能不断往上加新东西,不能删旧东西,这导致了语言变得非常的臃肿。同一个功能有很多写法,比如初始化变量:

int a = 1; int a(1); int a{1}; auto a = 1;

同时,这也导致错误设计永远无法被删除,比如 NULL、C 风格数组、旧式指针用法等,这就导致开发者必须同时理解新旧好几套东西。

可以说兼容性的包袱实在是太重了,持续演进下去,这个包袱还会更重,这也就导致标准技术委员变得会愈发保守,很多设计提案根本通过不了。

除此之外,编译器的开发也因此变得非常复杂,为了兼容几十年的代码:

  • 编译器必须理解很多历史规则
  • 必须保留旧语义的特殊情况
  • 处理各种奇怪但合法的写法

毕竟我不是 C++ 专家,所以我的吐槽其实是不够犀利的,感兴趣的话,可以去油管上看下 Lazo Velko 的这个视频《The worst programming language of all time》,足足两个小时的吐槽,而且有理有据,很下饭。

Go 过度保守的演进

Go 提出了兼容性承诺:Go 1 写的代码,未来 Go 1.x 都应该能运行,而这成为整个生态的重要基础。这样的好处是升级成本几乎为零,但是 Go 的演进速度实在是太慢。

早期接触 Go 的开发者一定知道,那时候 Go 连个包管理工具都没有,所有代码都写在$GOPATH/src目录下,无版本锁定、无依赖版本管理。

官方对此的回应是:无版本设计是刻意取舍。这其实很好理解,早期 Go 就是为了服务 Google 内部而研发的,无版本设计符合 Google 内部的情况。

也正因如此,在那时,社区涌现出了大量包管理工具,如:godep、glide、govendor 等。随着社区的不断反映,Go1.5 推出 Vendor 作为 GOPATH 补丁,但是依旧没解决无版本锁定和无依赖版本管理的问题,只是允许把依赖放进项目本地 vendor 目录。

而我们现在用的 Go Modules 是 Go1.11(2018)才作为实验性功能推出的,直到 Go1.16(2021)才永久默认启用。

除此之外,还有泛型,也是在社区的不断反映下,Go 团队才打破最初定下的不支持泛型的原则。然而,泛型的发展历程依旧是非常坎坷,最终在 Go1.18 才正式推出泛型,但是依旧很保守,比如不支持泛型方法。这也导致了推出泛型之后,几乎没人用的窘境。而泛型方法直到 Go1.26 才支持。

另外,Go 社区一直存在着诟病错误处理的声音,希望能像 Rust 的?那样进行错误传递,避免一次又一次的写:

iferr!=nil{returnerr}

虽然我对这种显式处理错误的方式没啥意见,也挺好的。但是社区的声音也是有道理的,类似于 Rust 的?处理方式也是显式的,而且更加的优雅。然而,不出意外,Go 官方依旧无视这一诉求。

也正因为演进过慢的原因,社区还自发分裂出 dingo 这个项目,在这里你可以使用?进行错误传递。不过,这个项目处于早期阶段,做下了解就好了。

Edition 机制让 Rust 不断进化

Rust 自 1.0 版本发布以来,始终承诺向后兼容,这意味着你在 2015 年写的 Rust 代码,在 2026 年的编译器上依然能正常运行,而这就需要依靠 Edition 机制来保障。

Edition 大约每三年发布一个版本,比如 Edition 2015、Edition 2018 等。这一点和 C++ 相似,比如 C++11、C++14 等。

而两者最大的区别是:C++ 的新标准需要长期背负所有历史规则,而 Rust 的 Edition 则允许语言逐步引入新规则,并逐步淡化旧写法

因此,对于新手来说,不需要纠结应该学习哪个 Edition。直接学习最新的 Edition 即可。

与此同时,Rust 还保证了不同 Edition 之间的互操作性。比如一个 Edition 2024 的项目,可以正常依赖 Edition 2015、2018 等的 crate。这里面的差异交由 Rust 工具链来处理,开发者并不需要操心。

而这也引出了一个重要的前提,Edition 之所以能够成功落地,一个重要原因在于 Rust 的工具链,如 cargo、rustc、rustfmt 等,全部都由官方统一维护与管理。

这里我将演示一个 Edition 2024 的项目调用一个 Edition 2015 的 crate,在这个 crate 里使用async作为变量名。

Edition 2018 引入关键字asyncawait,也就是说在 Edition 2015,它们是能作为变量名使用的:

letasync=123;// Edition 2015 合法

新建了一个 workspace 项目,目录结构如下:

├── Cargo.lock ├── Cargo.toml └── crates ├── new │ ├── Cargo.toml │ └── src │ └── main.rs └── old ├── Cargo.toml └── src └── lib.rs

根目录的Cargo.toml如下:

[workspace] resolver = "3" members = ["crates/new", "crates/old"]

old 的Cargo.toml如下:

[package] name = "old" version = "0.1.0" edition = "2015"

old 的lib.rs如下,这里使用async作为变量名,然后打印出来:

pubfndemo(){letasync=123;println!("The value of async is: {}",async);}

new 的Cargo.toml如下,这里我们引入 old crate:

[package] name = "new" version = "0.1.0" edition = "2024" [dependencies] old = { path = "../old" }

new 的main.rs如下,这里我们只是调用 old crate 的 demo 函数:

fnmain(){old::demo();}

我们到根目录执行cargo run命令,就能打印出结果了:

cargorun# The value of async is: 123

这就是 Rust 的核心设计哲学之一 Stability Without Stagnation(稳定而不停滞)。既允许语言不断进化,又不会无脑向后兼容,还尽可能保证导致生态不分裂。

结语

虽然这篇文章是夸 Rust 的 Edition 机制的,但是要记住这一切的前提是,Rust Edition 是站在巨人的肩膀上的,是吸取的很多前人的教训的。在未来,也还会有后来人站在 Rust 的肩膀上,吸取 Rust 的教训。

http://www.jsqmd.com/news/960764/

相关文章:

  • V5-83 宽全 PC 三防 LED 工矿灯产品介绍
  • 别再死记硬背GNN公式了!用PyTorch Geometric从零实现一个GraphSAGE(附完整代码)
  • LMS自适应滤波器Simulink一键仿真工程(含MATLAB脚本+公式推导Word文档)
  • 广东工程项目抗震支架、综合支架、成品支架选型五大核心依据
  • 2026最新诚信优选乌兰察布市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 2026长沙黄金回收行情分析 本地闲置黄金理财变现避坑指南 - 奢侈品回收测评
  • 微信投票活动发起全面指南:2026年避坑实测,这款零广告小程序最稳 - 微信投票小程序
  • AI健康数据孤岛破解方案:FHIR 4.0+OMOP CDM双标准映射实施手册(附医院POC代码库)
  • 网络排障实战:如何用中兴3928A的端口镜像抓包分析业务异常
  • CopilotKit:多平台代理框架,1分钟为应用添加AI功能!
  • PyTorch双判别器去雾模型:含训练代码、预训练权重与实测效果图
  • 用K210和STM32做个智能门禁:从硬件选型到代码调试的完整避坑指南
  • 电脑怎么录屏?告别捆绑软件和水印!3种工具从入门到进阶全搞定
  • 从功能块到实际动作:手把手拆解CODESYS EtherCAT电机控制程序(ST语言案例详解)
  • 高并发下接口耗时狂飙?这3个高可用设计让QPS从500冲到5000
  • Cosmos3:NVIDIA 把世界模型做成了“理解、生成、模拟、行动”的统一入口
  • 西安实体黄金回收就近上门:2026年6月金价973元/克,六家持证门店实测全攻略 - 余生黄金回收
  • 2026最新诚信优选乌兰浩特市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • BossMod FFXIV插件终极指南:从自动循环到战斗AI的完整解决方案
  • 用Python和PuLP搞定选址问题:从外卖站点到物流仓库的实战建模指南
  • 手把手教你为RViz添加中文地图菜单:点云与矢量地图加载功能集成指南
  • 上班族 AI 学习方案 第七周Python 自动化小脚本
  • 2026最新诚信优选十堰市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • VC/C++Builder/Delphi一键生成OPC DA服务器的开发套件
  • TMPGEnc 2.54.37.135 Windows版视频转码工具包:含VCD/SVCD/DVD多制式模板、双语帮助与完整配置文件
  • 谷歌允许美国大创作者和出版商认领搜索专属资料,整合多平台网络形象
  • Windows下Anaconda Navigator报错‘已运行’打不开?从杀进程到改代码的完整自救指南
  • 2026最新诚信优选乌鲁木齐市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 2026最新诚信优选水富市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY
  • 2026最新诚信优选石家庄市黄金回收白银回收铂金回收彩金回收高口碑靠谱门店TOP5权威排行榜+联系方式推荐 - 前途无量YY