Generic pointer type for `Rc`,` Box`, `Arc`

I have a struct that refers to a value (because is it ?Sized or very large). Of course, this value must live with the structure.
However, the structure should not limit the user to how to do this. Regardless of whether the user transfers the value to Box or Rc or makes it 'static , the value simply needs to be saved with the structure. Using the named lifetimes would be difficult because the link will be moved and can survive our struct . I am looking for a generic pointer type (if it exists / can exist).

How can a structure ensure that the reference value works as long as the structure exists, without specifying how?

Example ( is.gd/Is9Av6 ):

 type CallBack = Fn(f32) -> f32; struct Caller { call_back: Box<CallBack>, } impl Caller { fn new(call_back: Box<CallBack>) -> Caller { Caller {call_back: call_back} } fn call(&self, x: f32) -> f32 { (self.call_back)(x) } } let caller = { // func goes out of scope let func = |x| 2.0 * x; Caller {call_back: Box::new(func)} }; // func survives because it is referenced through a `Box` in `caller` let y = caller.call(1.0); assert_eq!(y, 2.0); 

Compiles, all is well. But if we don’t want to use Box as a pointer to our function (you can call Box pointer, right?), But something else, such as Rc , this will not be possible, since Caller restricts the pointer to Box .

 let caller = { // function is used by `Caller` and `main()` => shared resource // solution: `Rc` let func = Rc::new(|x| 2.0 * x); let caller = Caller {call_back: func.clone()}; // ERROR Rc != Box // we also want to use func now let y = func(3.0); caller }; // func survives because it is referenced through a `Box` in `caller` let y = caller.call(1.0); assert_eq!(y, 2.0); 

( is.gd/qUkAvZ )

Possible Solution: Deref ? ( http://is.gd/mmY6QC )

 use std::rc::Rc; use std::ops::Deref; type CallBack = Fn(f32) -> f32; struct Caller<T> where T: Deref<Target = Box<CallBack>> { call_back: T, } impl<T> Caller<T> where T: Deref<Target = Box<CallBack>> { fn new(call_back: T) -> Caller<T> { Caller {call_back: call_back} } fn call(&self, x: f32) -> f32 { (*self.call_back)(x) } } fn main() { let caller = { // function is used by `Caller` and `main()` => shared resource // solution: `Rc` let func_obj = Box::new(|x: f32| 2.0 * x) as Box<CallBack>; let func = Rc::new(func_obj); let caller = Caller::new(func.clone()); // we also want to use func now let y = func(3.0); caller }; // func survives because it is referenced through a `Box` in `caller` let y = caller.call(1.0); assert_eq!(y, 2.0); } 

Is this a way to go with rust? Using Deref ? It works as a minimum.

Am I missing something obvious?

This question did not solve my problem, since the value is practically not applicable as T

+5
source share
2 answers

As long as Deref provides the necessary functionality, AsRef and Borrow more suitable for this situation ( Borrow larger than AsRef in case of structure). Both of these features allow your users to use Box<T> , Rc<T> and Arc<T> , and Borrow also allows you to use &T and T Your Caller structure can be written as follows:

 use std::borrow::Borrow; struct Caller<CB: Borrow<Callback>> { callback: CB, } 

Then, when you want to use the callback field, you need to call the borrow() (or as_ref() ) method:

 impl<CB> Caller<CB> where CB: Borrow<Callback> { fn new(callback: CB) -> Caller<CB> { Caller { callback: callback } } fn call(&self, x: f32) -> f32 { (self.callback.borrow())(x) } } 
+3
source

It crashes with the current stable compiler (1.1), but not with the beta or nightly version (just use the last “Playpen” link and change the “Channel” setting at the top). I believe that Rc<Trait> support was only partial in 1.1; there were some changes that did not have time. This is probably why your code is not working.

To solve the question of using Deref for this ... if dereferencing a pointer is all you need ... is mandatory. It really is a question of whether your chosen trait supports the operations you need. If yes, great.

As an aside, you can always write a new attribute that expresses the exact semantics that you need and implement it for existing types. From what you said, in this case it does not seem necessary.

+1
source

All Articles