我有一个可以从某个索引提供字节的对象的特征。这些可能是文件、正在跟踪的进程、其他字节提供程序上的缓存等:
use std::result::Result;
use std::io::Error;
trait ByteProvider {
fn provide_bytes(&mut self, index: usize, dest: &mut[u8]) -> Result<usize, Error>;
}
struct ZeroProvider { }
impl ByteProvider for ZeroProvider {
fn provide_bytes(&mut self, _index: usize, dest: &mut[u8]) -> Result<usize, Error> {
dest.iter_mut().for_each(|e| *e = 0);
Ok(dest.len())
}
}
我还有一组小部件,可用于实现 ByteProvider 特征的任何泛型类型:
struct HexDump<T: ByteProvider> {
provider: T
}
struct Disassembler<T: ByteProvider> {
provider: T
}
impl<T: ByteProvider> HexDump<T> {
pub fn new(provider: T) -> Self { Self { provider } }
pub fn dump(&mut self) {
let mut bytes = [0; 16];
self.provider.provide_bytes(0, &mut bytes).unwrap();
println!("{}", bytes.iter().map(|e| format!("{:02x}", e)).collect::<Vec<String>>().join(" "));
}
}
impl<T: ByteProvider> Disassembler<T> {
pub fn new(provider: T) -> Self { Self { provider } }
pub fn disassemble(&mut self) {
println!("Disassembly");
}
}
这很好用:
fn main() {
let provider = ZeroProvider {};
let mut dumper = HexDump::new(provider);
dumper.dump();
}
...但是,我希望对同一数据有多个视图:
fn main() {
let provider = ZeroProvider {};
let mut dumper = HexDump::new(provider);
let mut disassembler = Disassembler::new(provider);
dumper.dump();
disassembler.disassemble();
}
但是这当然不是有效的 Rust,所以我转向引用计数智能指针来寻求帮助,期望它能够工作:
use std::rc::Rc;
fn main() {
let provider = Rc::new(ZeroProvider {});
let mut dumper = HexDump::new(Rc::clone(&provider));
let mut disassembler = Disassembler::new(Rc::clone(&provider));
dumper.dump();
disassembler.disassemble();
}
但是,编译器不喜欢这样:
27 | impl<T: ByteProvider> HexDump<T> {
| ^^^^^^^^^^^^ ----------
| |
| unsatisfied trait bound introduced here
...
error[E0599]: the method `dump` exists for struct `HexDump<Rc<_, _>>`, but its trait bounds were not satisfied
--> src/main.rs:48:12
|
19 | struct HexDump<T: ByteProvider> {
| ------------------------------- method `dump` not found for this struct
...
48 | dumper.dump();
| ^^^^ method cannot be called on `HexDump<Rc<_, _>>` due to unsatisfied trait bounds
...反汇编程序有类似的错误,我无法破译。我错过了什么?
我认为问题是 Rc 没有实现我的特征,但它没有公开其嵌套对象接口吗?
我希望小部件(HexDump 和反汇编器)不要知道它们的字节提供程序正在被共享(如果可能的话)。这能实现吗?
如评论中所述,预期用途意味着
ByteProvider
是在给定时间使用的多个小部件之间共享。.provide_bytes()
函数应该使用 shared 引用 (&self
) 而不是 exclusive 引用 (&mut self
)。ByteProvider
的 shared引用(而不是拥有它)。
ByteProvider
必须比小部件更长寿。
对于
ZeroProvider
示例,没有问题,因为它没有数据成员,所以没有什么可以改变。&self
就会出现问题。CountProvider
示例所示,内部状态(为简洁起见,这里使用一个简单的整数)嵌入到 RefCell
中,以便仅在需要时可变地借用此内部状态(多线程上下文中的等效项是RwLock
)。
trait ByteProvider {
fn provide_bytes(
&self,
index: usize,
dest: &mut [u8],
) -> Result<usize, Box<dyn std::error::Error>>;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct ZeroProvider {}
impl ByteProvider for ZeroProvider {
fn provide_bytes(
&self,
_index: usize,
dest: &mut [u8],
) -> Result<usize, Box<dyn std::error::Error>> {
dest.iter_mut().for_each(|e| *e = 0);
Ok(dest.len())
}
}
struct CountProvider {
count: std::cell::RefCell<u8>,
}
impl CountProvider {
fn new() -> Self {
Self {
count: std::cell::RefCell::new(0),
}
}
}
impl ByteProvider for CountProvider {
fn provide_bytes(
&self,
_index: usize,
dest: &mut [u8],
) -> Result<usize, Box<dyn std::error::Error>> {
let mut count = self.count.borrow_mut();
dest.iter_mut().for_each(|e| {
*e = *count;
*count += 1;
});
Ok(dest.len())
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct HexDump<'a, T: ByteProvider> {
provider: &'a T,
}
impl<'a, T: ByteProvider> HexDump<'a, T> {
pub fn new(provider: &'a T) -> Self {
Self { provider }
}
pub fn dump(&mut self) {
let mut bytes = [0; 16];
self.provider.provide_bytes(0, &mut bytes).unwrap();
println!(
"Dumping {}",
bytes
.iter()
.map(|e| format!("{:02x}", e))
.collect::<Vec<String>>()
.join(" ")
);
}
}
struct Disassembler<'a, T: ByteProvider> {
provider: &'a T,
}
impl<'a, T: ByteProvider> Disassembler<'a, T> {
pub fn new(provider: &'a T) -> Self {
Self { provider }
}
pub fn disassemble(&mut self) {
let mut bytes = [0; 16];
self.provider.provide_bytes(0, &mut bytes).unwrap();
println!("Disassembling {:?}", bytes);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fn main() {
let provider = ZeroProvider {};
let mut dumper = HexDump::new(&provider);
let mut disassembler = Disassembler::new(&provider);
dumper.dump();
disassembler.disassemble();
//
let provider = CountProvider::new();
let mut dumper = HexDump::new(&provider);
let mut disassembler = Disassembler::new(&provider);
dumper.dump();
disassembler.disassemble();
}
/*
Dumping 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Disassembling [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Dumping 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
Disassembling [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
*/