如何在将值传递给接收impl Trait的函数后保留所有权?
解决Rust中传递impl Trait参数后保留所有权的问题
问题场景
传递值给以impl Trait为参数的函数后,想保留原变量的所有权,但直接传值会导致所有权转移,后续无法使用原变量;尝试传引用也没解决问题,原代码报错如下:
trait Noise{ fn make_noise(&self); fn call_by_name(&self); } struct Person { name: String, } impl Noise for Person{ fn make_noise(&self){ println!("Hello"); } fn call_by_name(&self) { println!("Hey, {:?}, how are you doing?", self.name) } } fn talk(noisy: impl Noise){ noisy.make_noise(); } fn main() { let john_person = Person { name: String::from("John") }; talk(john_person); john_person.call_by_name(); // 这里报错:已失去所有权 }
问题原因
fn talk(noisy: impl Noise)的参数要求接收所有权,调用talk(john_person)时,john_person的所有权会被转移到函数内部,函数执行完毕后该值会被销毁,main函数里自然无法再访问它。
解决方案
因为你的Noise trait方法都是基于&self(只读引用)实现的,根本不需要获取所有权,所以只需修改函数参数为引用类型的impl Trait即可:
- 方案1:使用
&impl Noise作为参数
直接让函数接收一个实现了Noisetrait的引用,这样不会转移所有权:
// 修改talk函数 fn talk(noisy: &impl Noise){ noisy.make_noise(); } // main里传引用 fn main() { let john_person = Person { name: String::from("John") }; talk(&john_person); john_person.call_by_name(); // 正常执行,所有权仍在main中 }
- 方案2:使用
impl Noise + ?Sized(更灵活的写法)
如果想让参数同时支持引用和其他非Sized类型,也可以这么写:
fn talk(noisy: &(impl Noise + ?Sized)){ noisy.make_noise(); }
调用方式和方案1一致,传&john_person即可。
为什么传引用之前没解决?
如果你之前直接传引用但报错,大概率是没修改函数参数的类型——必须让函数明确接收引用类型的impl Trait,而不是继续用impl Noise(它只接收拥有所有权的值)。
内容的提问来源于stack exchange,提问作者EscFox
相关产品推荐
相关产品推荐

