Rust中如何避免Box传递时的所有权转移问题?
问题
我有一个方法需要接收持有实现了std::io::Write trait的结构体的Box。程序里用它写入stdout,测试时想让它写入缓冲区并生成字符串验证结果。
程序中的调用代码:
let stdOutWriter = Box::new(io::stdout()); write_output(&mut results, stdOutWriter);
其中write_output内部会调用:
let mut wtr = csv::Writer::from_writer(writer);
测试时我尝试这样调用:
let writer = Box::new(io::BufWriter::new(Vec::new())); write_output(&mut results, writer).unwrap(); let bytes = Box::new(writer.into_inner().unwrap()); // 后续计划验证该字符串 let string = String::from_utf8(*bytes).unwrap();
问题是write_output会消耗writer,导致无法调用writer.into_inner()。于是我改成传递引用:
let mut writer = Box::new(io::BufWriter::new(Vec::new())); write_output(&mut results, &mut writer).unwrap();
但出现类型不匹配错误:
expected mutable reference
&mut Box<(dyn std::io::Write + 'static)>
found mutable reference&mut Box<BufWriter<Vec<u8>>>
补充:write_output的签名为:
fn write_output(results: &HashMap<u16, ResultRecord>,writer: &mut Box<dyn io::Write>) -> Result<(), Box<dyn Error>>
解决方案
方法一:调整write_output的参数类型(推荐)
把write_output的参数从&mut Box<dyn io::Write>改成&mut dyn io::Write,这样无论是具体类型的引用还是 trait 对象的引用都能传递,灵活性更高:
use std::collections::HashMap; use std::io; use std::error::Error; fn write_output(results: &HashMap<u16, ResultRecord>, writer: &mut dyn io::Write) -> Result<(), Box<dyn Error>> { let mut wtr = csv::Writer::from_writer(writer); // 原有业务逻辑... wtr.flush()?; Ok(()) }
测试时可以正常持有BufWriter,调用后取出内部的Vec:
let mut writer = io::BufWriter::new(Vec::new()); write_output(&results, &mut writer).unwrap(); let bytes = writer.into_inner().unwrap(); let string = String::from_utf8(bytes).unwrap(); // 执行字符串验证逻辑...
生产环境调用无需额外修改,直接传标准输出的可变引用即可:
write_output(&results, &mut io::stdout()).unwrap();
方法二:不修改函数签名,手动转换 trait 对象
如果无法修改write_output的签名,可以先把具体类型的Box转为Box<dyn io::Write> trait 对象,再传递可变引用:
let mut writer: Box<dyn io::Write> = Box::new(io::BufWriter::new(Vec::new())); write_output(&results, &mut writer).unwrap(); // 向下转换为具体类型并取出内部Vec let buf_writer = *writer.downcast::<io::BufWriter<Vec<u8>>>().unwrap(); let bytes = buf_writer.into_inner().unwrap(); let string = String::from_utf8(bytes).unwrap();
这种方式需要处理downcast的类型匹配错误,不如第一种方法简洁直观。
内容的提问来源于stack exchange,提问作者jacob
相关产品推荐
相关产品推荐

