Rust中防御性拷贝的适用场景及常见开发不良实践有哪些?
什么时候使用拷贝是合理的
- 拷贝成本极低的场景:比如实现了
Copytrait的原生类型(i32、bool、char等,全部栈上存储,拷贝成本几乎可以忽略),直接拷贝比维护生命周期省心太多,完全没必要纠结引用传递。 - 代码可读性要求远高于性能要求的场景:如果生命周期标注会让代码复杂度陡增,且拷贝的对象本身不大、拷贝频次不高的情况下,优先保证代码可维护性,拷贝是完全可接受的选择。
- 并发场景下需要跨线程传递数据,且不想处理引用计数、锁的开销时:拷贝一份独立的数据能避免复杂的同步逻辑,在数据量不大的前提下性价比极高。
- API兼容性要求:如果要对接的第三方库接口要求持有所有权,没有对应接收引用的重载,直接拷贝是最省事的适配方案。
不拷贝就会触发move时的处理建议
优先按优先级判断,不要直接上来就拷贝:
- 先看能不能传引用:如果接收方不需要所有权,只需要读/写,优先传
&/&mut,完全避免move和拷贝的问题。 - 再看能不能用智能指针共享所有权:比如
Rc/Arc,如果是多个地方需要只读访问同一个大对象,用引用计数的开销远低于拷贝大对象的开销。 - 前两个都走不通的时候再拷贝:比如确实需要独立的可变副本,或者共享所有权带来的同步开销比拷贝还高,这时候就放心拷贝。
Rust常见不良实践整理
- 滥用
unwrap()/expect():除了开发阶段调试、或者100%确定Option/Result一定有值的场景,正式代码里应该做好错误处理,直接unwrap会导致程序毫无预兆地panic。 - 过度使用动态分发:明明可以用泛型实现静态分发获得更高性能,非要全用
Box<dyn Trait>,平白增加运行时开销。 - 不必要的
to_string()调用:很多场景下只需要&str就能完成操作,没必要特意转成String产生额外的堆分配。 - 忽略编译器提示的Clippy警告:Clippy给出的优化、规范建议绝大多数都是合理的,主动关闭Clippy或者无视警告很容易写出不规范、有性能问题的代码。
- 滥用
unsafe:明明Rust安全抽象就能实现的功能,非要用unsafe实现,平白增加内存安全风险。 - 结构体字段过度公开:不需要对外暴露的字段全部设为
pub,破坏封装性,后续修改内部逻辑很容易出现兼容性问题。
关键字转义是否属于不良实践
关键字转义(也就是用r#前缀使用Rust关键字作为标识符,比如let r#fn = 1;)绝大多数场景下都属于不良实践,只有两种例外:
- 做代码生成、FFI绑定的时候,对接的外部语言的标识符刚好是Rust关键字,这时候用转义是不可避免的。
- 特定领域的DSL里必须用对应领域的通用术语,而该术语刚好是Rust关键字的场景。
除了上述两种场景,刻意用关键字作为标识符会严重降低代码可读性,属于典型的不良实践。
内容的提问来源于stack exchange,提问作者Rafaelplayerxd YT
相关产品推荐
相关产品推荐

