Rust中如何实现「引用现有值或新建值后引用」的惯用写法
Rust 中实现「复用现有引用/创建新值后取引用」的优雅方案
问题场景
Rust 开发中常遇到这类逻辑需求:
- 满足特定条件时,直接使用已经存在的引用
- 不满足条件时,创建一个新的所有值(owned value),再使用指向这个新值的引用
最直观的写法会触发生命周期编译错误:
let variable = &some_ref; let variable = if something { let new_variable = create_something(); &new_variable // 编译报错:`new_variable` 存活时间不足,if 分支结束就会被 drop,返回的是悬空引用 } else { variable }; // 后续使用 variable
不少开发者为了绕开这个错误,会选择把后续使用变量的逻辑完整复制到两个分支中,比如实际开发中的图片处理场景:
let source = &source; if is_position_negative(x, y) { let source = crop(source, x, y); overlay_with_u32(destination, &source, x, y); } else { overlay_with_u32(destination, source, x, y); };
这种写法在后续逻辑复杂时会产生大量重复代码,维护成本很高。
符合 Rust 惯用法的解决方案
核心原则很简单:让新创建的 owned 值的生命周期覆盖引用的整个使用范围,不要让值在 if 分支内部就被销毁。常用的实现有两种,都不需要重复写业务逻辑。
方案1:局部作用域提前声明占位变量(无额外依赖,最轻量)
在 if 逻辑的外层提前声明存储新 owned 值的变量,分支内仅做赋值操作,最后统一获取引用:
let original_ref = &some_ref; // 提前声明占位变量,生命周期覆盖后续所有引用使用的范围 let new_owned_val; let variable = if something { new_owned_val = create_something(); &new_owned_val } else { original_ref }; // 后续直接使用 variable 即可,无生命周期问题
对应之前的图片处理场景,改造后代码如下:
let original_source = &source; let cropped_source; let source_ref = if is_position_negative(x, y) { cropped_source = crop(original_source, x, y); &cropped_source } else { original_source }; overlay_with_u32(destination, source_ref, x, y);
这种写法没有任何额外抽象,编译器能完全优化,运行时没有额外开销,适合局部临时使用的场景。
方案2:使用标准库 Cow 类型(语义更清晰,适合跨 scope 传递)
如果逻辑需要跨函数传递、或者后续存在修改值的需求,可以使用标准库提供的 Cow(Clone-on-Write,写时克隆)枚举,它天生就是为「要么借用引用、要么持有所有权」的场景设计的:
Cow::Borrowed(&T)存储一个借用的引用Cow::Owned(T)持有一个 owned 值Cow自动实现了Deref<Target = T>,可以直接当作&T使用,不需要手动解引用
示例代码:
use std::borrow::Cow; // 声明时不需要额外占位变量,直接在分支中返回对应的 Cow 枚举即可 let variable: Cow<'_, SomeType> = if something { Cow::Owned(create_something()) } else { Cow::Borrowed(original_ref) }; // 直接使用 variable,会自动解引用为 &SomeType // 比如调用 variable.some_method() 和用普通引用的效果完全一致
对应图片处理场景的写法:
use std::borrow::Cow; let source_ref: Cow<'_, [u32]> = if is_position_negative(x, y) { Cow::Owned(crop(source, x, y)) } else { Cow::Borrowed(source) }; overlay_with_u32(destination, &source_ref, x, y);
写法选择参考
- 仅在单个局部作用域使用时,优先选方案1,代码最轻量无额外抽象
- 需要跨函数传值、后续可能涉及修改值的场景,选方案2,语义更明确
注:最开始的直观写法报错是 Rust 内存安全机制的正常校验——分支内声明的变量作用域仅在分支内部,分支结束值就会被自动释放,此时返回引用必然指向无效内存,编译器会直接拦截这类风险。
内容的提问来源于stack exchange,提问作者antonmelnyk
相关产品推荐
相关产品推荐

