Rust会火,前后端工程师和全栈开发者要知道的2023历史临界点及编程语言未来趋势

2023年 9月 29日 36.4k 0

Rust诞生已经有17年了(2006年至今,从高中毕业到参加工作10多年,时间过得好快,学习Rust已经是第2年,Rust也不再是那个襁褓里的玩具编程语言),最近我考察了将团队的开发技术栈从Python生态转到Rust生态的可行性。先说结论:99%可行。

Rust生态目前的规模

不是100%可行,因为Python生态的一些名库还未提供Rust版本,但请注意到,那些Python生态有的功能,Rust生态里也大部分有了。毕竟Rust已经17岁了,经过17年的积累,Rust终于快到“成年”了。比如Rust的线上Crate仓库lib.rs现有127219个包,Python的pypi.org仓库现有484174个包(以上统计截至2023年9月28日)、而Go语言在pkg.go.dev上有超过 170000 个包(截至2023 年 4 月)。

为什么我决定从Python转换到Rust?

Python是一种语法简练直观的语言,新手很容易上手,很多人像我一样,从最开始使用C/C++编程需要处理位运算、指针、字符串转换等的底层编程范式中感到有处理不完的细节、越来越复杂的C++语法,到喜欢上Python的灵活表达和快速实现上层业务逻辑功能。

然而随着项目规模和复杂程度增加,Python的这些优点不知不觉包含了相关的缺点,特别是Python的弱类型、函数返回值的隐式转换、无法真正编译出二进制可执行文件进行安全分发,等等一系列问题,给项目的多人协作和部署维护等场景带来了很多麻烦。比如Python项目的某个普通的数据查询函数

def get_db_value_with_param(from, param)

在项目初期暂时未被调用,项目初期该函数经过测试功能符合预期,所以没写具体的用法注释,以为其他人能见名知义。该函数的入参也只是指定了名称,未注解参数类型、未注解返回值类型。

等到该项目在后面功能迭代的时候要用到这个函数时,只能通过看函数代码来判断用法。就可能出现至少5种隐患:

  • 隐患1:部分错误只能在运行时爆出,但为时已晚。
    未被调用的Python函数,即使该函数存在内部变量未定义等非致命的语法错误,也无法被立刻检测到(除非使用一些静态检查插件、或使用特定的IDE工具)。若没经过测试人员复测和修复,则运行时异常的发生将阻止函数内的后续代码的执行(Exception的保护作用)。但Python代码的这种惰性报错的特点,让项目隐藏了很多潜在【雷区】,难以被主动检测手段提前发现;

  • 隐患2:弱类型。
    当需要调用该函数时,无法快速确定入参的数据类型要求;难以确定是否有返回值,如何使用返回值;

  • 隐患3:隐式转换。
    当函数实际返回了str类型的返回值“1”,而代码并未将数据库或服务端返回的数据(函数返回值)转换为期望的值(错误处理不到位)就非常容易引起意料之外的效果。这个问题在python与数据库结合的时候更容易发生,如mysql 这种数据对字段的类型要求不严格的数据库,允许向列类型为varchar(10)的is_open字段插入数值,例如数值1插入到is_open字段后会被自动转换为字符串“1”存储。如果 is_open的列类型为 tinyint(1),而SQL插入字符串”1”,会被隐式转换为TINYINT(1)类型的数字1存储,即使插入时不会因为类型隐式转换而引发问题,也会在读取时因为各种原因引起误解,如下面的例子):
    SQL 操作

    insertinto db_param_info(from_param_key, param_type) values ("参数状态1", 1);  

python代码调用及输出:

status = 1 #status = get_db_value_with_param(from, param)
if True==status:
    print("获取数据成功")

输出结果:
获取数据成功

再看一段潜在问题代码:

status = "1" #status = get_db_value_with_param(from, param)
###未启用的代码 status = bool(status) #这里暂时未启用bool()的强制类型转换。
if True==status:
    print("获取数据成功")#没有任何输出结果!!!

若从数据库查询到的为”1” 则本段代码会判断为未取得数据(实际”1”的本意也是代表取数成功)。如果get_db_value_with_param() 返回值为“1”,只能依靠bool(status) 或int(status) 强制转换为支持True/False比较的类型。但即使写成 def get_db_value_with_param(from, param)->bool 这种函数注解也没用,因为当函数内部返回的数据是字符串,而python不会根据注解(->bool)将字符串转为bool类型返回,而直接返回的仍是字符串类型的“1”。

这是python的返回值隐式转换的最大问题:返回值没有强制符合注解类型。也就是Python的函数注解也不可靠!

开发者想当然(或疏忽)认为函数返回的是数字类型的 1 而实际返回的是字符串类型的“1”,由于Python代码此类错误只在运行时才触发,无法获得Rust或Go语言在编译器即获得报错信息的优势。从而降低了Python项目整体质量,增加了一些隐形问题的排查解决成本,浪费了大量精力。

Python上述5个隐患是难以避免的。而在Go或Rust语言中是完全可以避免的,因为代码编译时就能发现此类错误,尤其Rust的编译器的错误提示非常详细非常友好。

所以Python的代码的维护成本不低。尤其在多人协作开发时,这个问题更加突出。

  • 隐患4:无法生成真正的二进制可执行文件。
    尽管.pyc作为python代码的字节码可以加速运行,但pyc容易被反编译,无法满足对抗反编译的生产级别要求;而python的cython版本有特定版本要求,无法轻松将python项目编译为可执行文件,只要稍大的项目经cython编译非常容易出现各种报错,cython依赖于复杂的C环境。即使是新晋的Mojo语言团队也承认Python的完整支持是一件极其复杂且耗时的工作。

所以我们看到Mojo、go-plus(Go+)等新型编程语言的出现,宣称要兼容python生态,又支持编译为二进制文件以大幅提升软件性能,说明越来越多人认识到传统的Python需要做出改变。但Mojo乃至go-plus距离生产广泛认可的程度,还有待时日。

总之,Python无法像go和Rust、Zig、Nim、V等语言那样轻松实现跨平台编译+二进制可执行文件部署,产生了多种负面问题。

  • 隐患5:动态类型语言的代码自动完成功能受限,降低了开发效率。
    Python之类的动态类型语言,由于编码时开发工具难以准确确定类型(除非额外指定类型),那么开发工具对代码的【自动完成功能】就非常受限,这间接影响了开发效率。
    而静态类型语言的链式调用非常顺畅,只要是确定了类型,那么相应的可自动完成的函数和变量就都明确了,【自动完成功能】可谓新的静态类型语言的标配。

Python的以上5点隐患,在Go和Rust上都得到了彻底解决。

Rust和Go已经是趋势

语言和库只是工具,关键在于语言擅长于解决问题的能力、在于它能为使用者提高多少效率、最终能为社会创造多少价值。而Rust因为实用的能力,目前(2023年)正处在Rust大规模应用爆发的临界点。大量软件团队正在用Rust/Go重写软件。
下面从三个具有代表性的应用实例以及一些Rust语言大事件,向读者分享下这个“Rust临界点”的观点。

Rust能复用C/C++现有的生态

例如,C++有Qt库,是跨平台桌面图形软件(GUI)开发的集大成者,而Rust有rust-qt项目,100%支持QT-C++原有的底层库和功能,通过相关的crate包可供rust应用调用QT-C++库的所有功能。这里有个采用rust-qt开发的图片文字识别软件的开源案例demo

【实例1】:
github.com/kerneltrave… 。

图片

相比Go语言的qt库(著名开源项目github.com/therecipe/q… 已停止更新,Go的 therecipe/qt 的开发环境配置极其复杂 github.com/therecipe/q… ,除非直接使用官方提供的Docker环境),而Rust实现的 Rust-qt 开发的准备工作难度更低(参见 rust_qt_gui_paddle_ocr_example 的Readme.md),Rust-qt不需要自己编译qt库,也不需要各种复杂的环境变量设置,基于cargo配置文件就可以自动拉取依赖,编译运行,得到rust-qt开发的桌面软件。配合代码编辑器的【自动完成】功能,开发体验丝滑,适合熟悉QT的C++开发发人员转Rust后继续使用QT。

Rust能整合并取代C/C++的开发方式

无论在C/C++为主流的Linux内核开发、Windows驱动开发、嵌入式开发领域,还是Web前端开发、移动端开发、游戏开发、AI开发、区块链开发、IoT开发、桌面开发、服务器开发等各类软件领域,都已存在一些实用的Rust方案。从底层系统到上层应用,Rust都适合作为开发语言,而且由于Cargo工具降低了项目的工程复杂度,大量的crate库可供选用,Rust的开发体验越来越丝滑(站在巨人的肩膀上,好东西拿来主义:Rust有很多方面跟Typescript很像,而Cargo的项目配置文件Cargo.toml和crate生态,可能是学习了npm生态和packages.json的思路)。

Rust既可以通过ffi方式调用C++库、通过cxx直接复用C++代码;还可以直接调用dll和so以及dylib动态库暴露的接口。

Rust能开发动态库以丰富C/C++/Python/Nodejs的生态

Rust支持通过pyO3开发Python模块来丰富Python生态;

Rust支持通过neon开发npm包来丰富nodejs生态。

Rust支持生成.dll和.so等动态库(Rust对动态库的支持比Go要成熟,因为Rust可以跨平台生成目标系统的动态库,而Go的动态库机制,对跨平台生成动态库的支持尚不友好)。

更重要的是Rust开发的Python/npm的包运行性能比python或js语言实现的包的性能有大幅提升。

Rust能兼容nodejs/npm生态并取代Electron 进行跨平台桌面软件开发

经过我的验证,目前的Rust的 tauri对跨平台的支持、对现有的nodejs生态的无缝迁移和复用性,已经达到可以用于生产环境的效果(2023年9月,tauri的最新版本为1.4)。

前端开发人员可使用tauri+npm生态开发跨平台桌面软件,支持热重载(hot-reload),将已有的web资源复用到桌面软件上,加速业务推进。

一套基于nodejs的前端代码,经过稍微修改就可以基于Electron生成桌面软件,但Electron始终存在若干问题,如运行时内存占用过大、安装包体积大(如压缩后体积往往仍在70MB以上 )。

而同样的前端代码,经过稍微修改后,也可以在Rust开发的tauri环境下开发和编译为桌面软件,包体积可控制在10MB上下,且支持Windows7系统和更高版本的windows系统、支持Linux和Mac,界面还原度保持一致。
与Electron和Flutter的开发测试体验类似,tauri的开发测试过程也支持热重载(hot-reload):将【实例2】中的任意界面文字在代码中修改后,调试环境运行的tauri界面中的文字马上更新,而无需重启软件。这大大加快了开发效率。

【实例2】采用Rust+tauri+React18、React-Router V6、React-Hooks、Redux、TypeScript、Vite2、Ant-Design开发的后台管理web转桌面软件,其中基本不需要写Rust代码。项目地址:gitee.com/kjpioo2006/…  (什么叫 稍微修改即可转变为桌面软件?可参考该项目的9月28号的4个提交记录 就明白了。基本上都是配置文件的修改,常规功能都由前端代码完成,几乎可以不改动Rust代码文件)

图片

支持皮肤色调切换

图片

桌面软件延续了原Web元素的操作体验:用户头像下拉菜单、左侧菜单

图片

将Web前端擅长的监控大屏带入桌面软件

图片

用户引导功能

图片

基于Echarts的图表展示,延续了npm生态的丰富界面能力

图片

基于Echarts的图表展示,延续了npm生态的丰富界面能力

图片

支持内嵌网页浏览功能

【实例3】基于Rust开发的汉字转拼音库:  github.com/mozillazg/r… 

rust开发的汉字转拼音nodejs模块: github.com/Brooooookly…

Rust还能开发 VS-code 插件

由于对js和nodejs/npm 生态的良好支持,Rust可以开发VS-code插件,著名的rust-analyzer 就是Rust开发的VS-code插件,性能极好!

在Crate仓库lib.rs 正在不断增加的127219多个包中,总有适合你项目的,如果没有,那么是时候你自己写一个!因为2023年,正是基于Rust的应用范围爆发的临界年。

Rust 2022-2023年大事记

2022年12月13日 Linux 内核 6.1 发布,Linux的内核开始支持Rust编写内核代码。

2023年中,微软将Rust引入Windows内核,已将Rust开发的内核GDI图形模块应用于Windows11生产系统。

图片

2023年9月26日微软开源了windows-drivers-rs,以后用 Rust 开发 Linux/ Windows 驱动程序将变成常态化。

还有很多Rust大事,……不再赘述

在这个临界点上,把握趋势,为未来作好铺垫。无论你是前端开发者、后端开发者、还是独立全栈工程师,不要觉得网上别人都说Rust难,只有你亲自动手尝试用Rust解决实际业务问题了,你才能掌握和体会到Rust是怎样的。我学了,我的体会是,当你用心学了做了那么Rust也不难。供参考。

本文由【开源软件技术咨询】原创,公号【深入理解Linux】。

附录:

  • Rust 的crate包仓库:lib.rs/
  • Python的pip包仓库:pypi.org/
  • Go包仓库:pkg.go.dev/
  • 2022年12月13日 Linux 内核 6.1 发布,允许开发者用 Rust 编写内核代码:www.kernel.org/doc/html/la…
  • 2023年9月26日,《微软开源 windows-drivers-rs,用 Rust 开发 Windows 驱动程序》:www.oschina.net/news/259564…
  • 2023年8月,huggingface开源了其机器学习框架Candle: www.infoq.cn/article/fMB…
  • Rust通过ritual使用 C++现有的库:github.com/rust-qt/rit…
  • Rust通过cxx调用C++代码:cxx.rs/
  • rust通过ffi调用C/C++的资源:rustcc.cn/article?id=…
  • Rust开发python模块: github.com/PyO3/pyo3
  • vscode插件 rust-analyzer 采用Rust+Typescript开发,性能强悍的用于IDE的rust开发辅助工具: github.com/rust-lang/r…
  • Rust的neon开发nodejs/npm模块:github.com/neon-bindin…
  • 采用rust-qt开发的图片文字识别软件demo:github.com/kerneltrave… 
  • rust-qt的官方examples:github.com/rust-qt/exa…
  • 采用Rust+tauri+React18、React-Router V6、React-Hooks、Redux、TypeScript、Vite2、Ant-Design开发的后台管理web转桌面软件,其中基本不需要写Rust代码:gitee.com/kjpioo2006/…
  • 基于Rust开发的汉字转拼音库:github.com/mozillazg/r… 
  • rust开发的汉字转拼音nodejs版: github.com/Brooooookly…

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论