如何以Rust惯用方式实现适配可变与不可变引用的函数?
问题描述
我想要构建一个可适配传入可变或不可变引用的函数/方法,尝试了如下实现:
trait TryAsMut<'a, T> where T: 'a { fn try_as_mut(self) -> Result<&'a mut T,&'a T>; } impl<'a, T> TryAsMut<'a, T> for &'a T { fn try_as_mut(self) -> Result<&'a mut T,&'a T> {Err(self)} } impl<'a, T> TryAsMut<'a, T> for &'a mut T { fn try_as_mut(self) -> Result<&'a mut T,&'a T> {Ok(self)} } fn option_inc<'a>(value: impl TryAsMut<'a, usize>) -> Option<usize> { match value.try_as_mut() { Ok(u) => { *u += 1; None }, Err(u) => { Some(*u + 1) }, } } fn main() { let mut u = 5; println!("u + 1 = {}", option_inc(&u).unwrap()); option_inc(&mut u); println!("u = {u}"); }
运行结果:
Compiling playground v0.0.1 (/playground) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58s Running `target/debug/playground` Standard Output u + 1 = 6 u = 6
该实现可正常运行,但我想知道是否存在符合Rust惯用风格的实现方式?
惯用实现方案
你的实现逻辑通顺,但在Rust社区中,针对这种兼容可变/不可变引用的场景,有两种更贴合惯用风格的做法:
1. 定义两个同名函数(推荐)
Rust支持基于参数类型的重载解析,直接为&usize和&mut usize分别实现同名函数是最直观、可读性最高的方案,完全符合Rust"显式优于隐式"的设计原则:
fn option_inc(value: &usize) -> Option<usize> { Some(*value + 1) } fn option_inc(value: &mut usize) -> Option<usize> { *value += 1; None } fn main() { let mut u = 5; println!("u + 1 = {}", option_inc(&u).unwrap()); option_inc(&mut u); println!("u = {u}"); }
编译器会自动根据传入的引用类型匹配对应的函数,无需额外抽象层,代码简洁易懂。
2. 结合标准库trait实现泛型函数
如果需要统一函数签名,可以借助标准库的AsRef和AsMuttrait,通过重载+泛型复用部分逻辑,适合复杂场景:
use std::borrow::{AsRef, AsMut}; // 处理可变引用的泛型实现 fn option_inc<T>(mut value: T) -> Option<usize> where T: AsRef<usize> + AsMut<usize>, { *value.as_mut() += 1; None } // 单独处理不可变引用 fn option_inc(value: &usize) -> Option<usize> { Some(*value + 1) } fn main() { let mut u = 5; println!("u + 1 = {}", option_inc(&u).unwrap()); option_inc(&mut u); println!("u = {u}"); }
内容的提问来源于stack exchange,提问作者FreD
相关产品推荐
相关产品推荐

