NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

受不了 Rust 这些问题,我将后端切换到了 Go

  • 2023-01-03
    北京
  • 本文字数:1767 字

    阅读完需:约 6 分钟

受不了Rust 这些问题,我将后端切换到了 Go

本文最初发布于 Level Up Coding 博客。


别激动!我能感受到你点击这篇文章时怀有的愤怒。我并不讨厌 Rust——在许多场景中,我都倾向于使用它。所有编程语言都是达成目的的手段。然而,就我要处理的场景而言,Rust 并不是很适合,我不得不把这个项目推倒重来,用 Golang 重写。


该项目是 Hasura 的一个简单的后端 webhook 服务。你可能不了解 Hasura,那是一个 Postgres 数据库封装器,可以即时提供 GraphQL API。对于像我这样独自开发个人兴趣项目的人来说,这非常方便:每个 REST 端点或 GQL 解析器都要编写的话会耗费大量的时间,而且每个模型的 CRUD 操作基本相同。当需要一些比较复杂的逻辑时,它就不那么有效了——为此,Hasura 允许你将 GQL 请求映射到自定义 webhook。举例来说,我就是用这种方法进行 S3 文件上传或身份验证。


问题 1:依赖注入难


Rust 依赖注入是一个有趣的问题。如果你需要一个具体的类型,如:

fn do_stuff(db: &Database) {    db.create(Stuff);         db.read(Stuff);}
复制代码


你必须给 do_stuff 传递一个 Database 实例;概莫能外!你不能“子类化”Database (Rust 没有子类的概念)。所以,如果你是一个不自己测试代码的程序员,那么这完全没问题;实际上,你只会有一个 Database 的实现,因此也就没有理由让这个函数接受 Database 以外的任何东西。


那我们测试人员呢?我们必须重写函数签名。Database 需要是 trait 类型的,然后我们把那个它在 mock 对象上实现。好吧,还不算太坏。事实上,在 Golang 中,我做的事情基本相同;那到底是从哪里开始有问题的呢?


问题 2:异步 Trait


在 Rust 中,异步很简单,trait 也很简单,但异步 trait 却有些困难。我在 Rust 中找到的大多数异步 trait 示例都用了 async_trait 宏。这很有帮助,我正在用它,体验还不错。


以下是我到目前为止对这个过程的一个总结:


  1. 编写一个结构;开心。

  2. 编写一个测试;意识到无法依赖注入。难过。

  3. 将结构转换为 trait;开心。

  4. 心满意足地依赖注入。

  5. 使用 mockall crate 自动生成 mock。非常非常开心!

  6. 做一个异步 http 调用。

  7. 需要用一个特殊的宏实现异步 trait。

  8. 意识到这个宏无法很好地与 Mockall 一起工作。

  9. 难过。


事后来看,这个问题是有办法解决的。也许在切换到 Go 之前我应该再试一次,但那时,下面这一点已经让我有点沮丧了……


问题 3:编译慢(致命一击)


Rust 的编译时间很糟糕。我们已经听过无数次了;不可能有一种无所不能却没有缺点的语言。那是不可能的——Rust 的缺点是难以理解的生命周期以及糟糕的编译时间。


我有一台漂亮耐用的笔记本电脑 M1 Mac,那可是一头老黄牛。在我的 Mac 上编译 Rust 绝对没有问题。通常,在编写服务器时,我会在本地开发,并且要保证每次有修改时,本地服务器会重新加载,让我可以在提交真正的单元测试之前非常快速地测试功能。两次试验之间需要进行大量的编译;可以接受!还是说,在 Mac 上编译 Rust 没有问题。


在容器里吗?还是算了吧。


对我来说,要编排许多本地服务而又不用费事在每个服务(Hasura、Web 钩子、mock s3、mock oauth 服务器……)中运行 npm run ,最简单的方法是有一个 docker-compose.yaml 文件可以运行所有这些东西。通常就是一个 docker-composition.dev.yaml 文件,因为我实际上并不使用 docker compose 进行部署。只在本地进行开发。然而,这有一个副作用,就是我的 Rust 代码需要在容器中编译,因为:必


  1. 须自动热重载。

  2. 必须在容器里开发。


我有两个选择:要么启动一个可能会跑死整台计算的巨大镜像,以便在其中编译 Rust 代码,要么就要与 3 分多钟的编译时间周旋。开发周期陷入停滞,让我感觉非常低效。我试着改变工作流程,在手动测试之前编写代码和测试,或者不使用自动热加载,但糟糕的是,我就是没能做到。


最后,我咬紧牙关,换成了 Go。让人怀念的 Rust:我非常喜欢编写 Rust 代码。我觉得它漂亮而富有表现力,实用而优雅。


如果我正在编写本地辅助库、性能敏感代码、任何不需要在容器中运行的后端服务……那么,Rust 会是我的第一选择。特别是如果我不需要说服其他任何人使用它。


对于我提到的问题,特别是最后一个问题,如果你有任何解决方法,请务必告诉我。我想让 Rust 回到项目中,我愿意回到旧版本,并将其提升到同等水平。


原文链接:https://levelup.gitconnected.com/why-i-switched-from-rust-to-go-on-the-backend-28bda21dbee9

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2023-01-03 18:0112655
用户头像
刘燕 InfoQ高级技术编辑

发布了 1112 篇内容, 共 493.8 次阅读, 收获喜欢 1967 次。

关注

评论

发布
暂无评论
发现更多内容

RocketMQ msgId与offsetMsgId释疑(实战篇)

Java 程序员 后端

RocketMQ 千锤百炼--哈啰在分布式消息治理和微服务治理中的实践

Java 程序员 后端

【Flutter 专题】12 图解圆形与权重/比例小尝试

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 11月日更

Redis常用命令总结

Java 程序员 后端

Redis(十八):服务器

Java 程序员 后端

RocketMQ 主从同步读写分离机制

Java 程序员 后端

RocketMQ消息丢失场景及解决办法(1)

Java 程序员 后端

Spring boot —— 创建parent工程

Java 程序员 后端

Redis安装与部署新手入门教程

Java 程序员 后端

Redis(二十六):Sentinel—

Java 程序员 后端

Redis(十六):事件

Java 程序员 后端

Spring Boot 中三种跨域场景总结,这篇必看!不看后悔系列

Java 程序员 后端

Redis持久化方式AOF技术原理?一文带你从底层彻底吃透

Java 程序员 后端

spring boot 自定义配置文件&参数绑定

Java 程序员 后端

Redis实现feed流(1)

Java 程序员 后端

Redis哨兵模式原理剖析,监控、选主、通知客户端你真的懂了吗?

Java 程序员 后端

redis数据迁移之redis-shake

Java 程序员 后端

Redis(十一):键的生存时间与过期时间

Java 程序员 后端

RocketMQ消息丢失场景及解决办法

Java 程序员 后端

SAP为Java 16贡献JEP 387 “弹性元空间”

Java 程序员 后端

Servlet 入门

Java 程序员 后端

Spring @Lookup实现单例bean依赖注入原型bean

Java 程序员 后端

RocketMQ消息轨迹-设计篇

Java 程序员 后端

Spring Boot + EasyExcel 导入导出,好用到爆!

Java 程序员 后端

Redis实现feed流

Java 程序员 后端

Redis小白入门教程

Java 程序员 后端

Redis的各种用途以及使用场景(1)

Java 程序员 后端

Redis的各种用途以及使用场景

Java 程序员 后端

RocketMQ一行代码造成大量消息发送失败

Java 程序员 后端

RocketMQ源码分析之NameServer

Java 程序员 后端

Serverless 如何在阿里巴巴实现规模化落地?

Java 程序员 后端

受不了Rust 这些问题,我将后端切换到了 Go_AI&大模型_Anthony Oleinik_InfoQ精选文章