实际问题(避免 A/B 场景):
我在 Arc 对象后面有一个很大的缓冲区:
pub struct LargeData {
data: Arc<Vec<u8>>,
}
我需要将
Read + Seek
版本传递给网络 API 作为 Box'ed 从函数返回(不复制整个缓冲区)。
首先,我尝试将光标设置为对 Vec 的引用:
fn open_for_read(&self) -> io::Result<Box<dyn ReadAndSeek>> {
Ok(Box::new(Cursor::new(self.data.as_ref())))
}
但是编译器正确地警告了该游标实际上可能比所有 ARC 实例的寿命都长。
我的第二个想法是将
Cursor
和 Arc
打包到新结构中并为其实现 Read + Seek
struct ReaderData {
data: Arc<Vec<u8>>,
cursor: Cursor<Vec<u8>>,
}
impl ReaderData {
fn new(source: &LargeData) -> Self {
let data = source.data.clone();
Self {
data,
cursor: Cursor::new(data),
}
}
}
// Read + Seek implementation that only passes into cursor Read and Seek
但是这次我遇到了更神秘的错误:
cursor: Cursor::new(data),
----------- ^^^^- help: try using a conversion method: `.to_vec()`
| |
| expected `Vec<u8>`, found `Arc<Vec<u8>>`
arguments to this function are incorrect
使用
to_vec()
会复制向量,这是我想避免的。
这是我放弃的地方。
我在这里遗漏了什么吗?我如何从
Read + Seek
制作 Arc<Vec<u8>>
对象?
Cursor
需要实现 AsRef<[u8]>
的类型。 Arc<Vec<u8>>
不幸的是没有,但你可以自己实现LargeData
:
#[derive(Clone)]
pub struct LargeData {
data: Arc<Vec<u8>>,
}
impl AsRef<[u8]> for LargeData {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
impl LargeData {
fn open_for_read(&self) -> Cursor<LargeData> {
Cursor::new(self.clone())
}
}
如果
LargeData
包含其他字段,您可以将 Arc<Vec<u8>>
提取到不同的结构体。