面向 Go 后端开发者的 Rust 阅读指南:无痛理解 Counterpoint
这个项目使用 Rust 编写,但它的设计深受一些高质量 Go 项目的启发:清晰的分层结构、显式接口、简单的并发模型,以及“正确性优先”的工程思维。
如果你已经习惯阅读 Go 的服务端代码,那么你其实已经理解了这个项目的大部分架构。本文的目标是帮助你把这些已有知识映射到 Rust 上,让你关注系统设计本身,而不是语法细节。
项目结构:Rust Crates vs Go Packages
如果你习惯用 Go package 的视角来看代码,那么 Rust 的目录结构可以这样理解:
-
api/→ HTTP 处理层(类似 Go 的net/httphandlers) -
application_port/→ 服务接口层(相当于 Go 的interface) -
application_impl/→ 服务接口的具体实现 -
domain_model/→ 领域结构体与业务规则 -
domain_port/→ 仓库(repository)接口定义 -
infra_*→ MySQL / Redis 等基础设施实现 -
server/→ 运行时组件(WebSocket、会话管理等)
如果这是一个 Go 项目,其中很多目录可能都会放在 internal/ 的子包下。
Rust Trait = Go Interface
Go 开发者看到 Rust 代码时最先注意到的通常是:
这其实就是 Go 中的:
Rust 的 trait 和 Go 的 interface 用法非常相似:
-
定义契约(contract)
-
隐藏具体实现
-
支持依赖注入(dependency injection)
所以阅读时可以直接把 trait 当成 interface 来理解。
Arc<T>:类似 Go 的共享引用
Rust 有严格的所有权规则,因此多个地方共享服务对象时通常会写成:
Arc<dyn AuthService>
对于 Go 开发者,可以理解为:
Arc 存在的原因是:Rust 没有 GC,需要显式管理共享所有权。
因此:
-
Go 可以自由共享指针
-
Rust 通过
Arc来安全共享
概念上,两者都是“共享的服务对象”。
Async Rust = Go Goroutines + Context
Rust 的异步代码看起来像这样:
tokio::spawn(async move {
notifier.run().await;
});
对应的 Go 写法就是:
模型是一样的:
-
轻量任务(lightweight tasks)
-
协作式调度(cooperative scheduling)
-
支持取消(cancellation)
Rust 通常使用:
CancellationToken
Go 使用:
context.Context
所以你可以把 Rust async 理解为:
“带 context 的 goroutine”。
错误处理:error vs Result
Go 的错误处理:
Rust 的错误处理:
语法不同,但哲学一致:
-
错误是值(errors are values)
-
必须显式处理
-
没有隐藏异常(no hidden exceptions)
本项目刻意避免复杂的错误技巧,保持错误流“简单可读”。
Warp Filters = Gin 的 Middleware Chain
在 Counterpoint 中,路由写法是:
这基本等价于 Gin:
Warp 使用 combinator 组合,而 Gin 使用 middleware 函数链,但结构是一样的:
-
提取请求参数
-
注入服务依赖
-
调用 handler
Go 开发者如何阅读这个项目
如果你来自 Go,我建议按以下顺序阅读:
-
从 application services 开始(核心用例层)
-
暂时忽略 async 语法,先跟着数据流走
-
把 trait 当作 interface
-
把 actor 当作“拥有状态的 goroutine”
-
重点关注:谁拥有状态?谁调用谁?
只要架构逻辑清楚,Rust 的语法细节就不容易造成障碍了。

浙公网安备 33010602011771号