问题
I have design issue that I would like solve with safe Rust that I haven't been able to find a viable solution. I can't use a RefCell
because you can't get a & reference to the data, only Ref
/ RefMut
.
Here is a simplified example with irrelevant fields / methods removed
use std::cell::RefCell;
use std::rc::Rc;
struct LibraryStruct {}
impl LibraryStruct {
fn function(&self, _a: &TraitFromLibrary) {}
}
trait TraitFromLibrary {
fn trait_function(&self, library_struct: LibraryStruct);
}
// I don't want to copy this, bad performance
struct A {
// fields...
}
impl TraitFromLibrary for A {
fn trait_function(&self, library_struct: LibraryStruct) {
// custom A stuff
}
}
// B manipulates A's in data
struct B {
data: Vec<A>,
}
struct C {
// This type doesn't have to be & for solution. C just needs immutable access
a: Rc<RefCell<A>>,
}
impl<'a> TraitFromLibrary for C {
fn trait_function(&self, library_struct: LibraryStruct) {
// custom C stuff
// Takes generic reference &, this is why Ref / RefCell doesn't work
library_struct.function(&self.a.borrow());
}
}
// B and C's constructed in Container and lifetime matches Container
// Container manipulates fields b and c
struct Container {
b: B,
c: Vec<C>,
}
fn main() {}
I would be able to solve this with Rc<RefCell<A>>
but I am being restricted from the library requiring &A
.
This produces the error:
error[E0277]: the trait bound `std::cell::Ref<'_, A>: TraitFromLibrary` is not satisfied
--> src/main.rs:33:33
|
33 | library_struct.function(&self.a.borrow());
| ^^^^^^^^^^^^^^^^ the trait `TraitFromLibrary` is not implemented for `std::cell::Ref<'_, A>`
|
= note: required for the cast to the object type `TraitFromLibrary`
回答1:
If a function has an argument which is a of type &A
, then you can call it with a reference to any type that dereferences to A
, which includes things like &Ref<A>
. The concept of one type dereferencing to another is captured by the Deref trait. This is also the reason why a function that accepts &str
can be called with &String
(String: Deref<Target = str>
).
So, if you keep a
as a Rc<RefCell<A>>
, you can fix your code quite easily like this:
library_struct.function(&*self.a.borrow());
Note that this dereferences A
and then reborrows it so that it can be coerced to a trait object.
来源:https://stackoverflow.com/questions/52124007/how-can-i-obtain-an-a-reference-from-a-rcrefcella