0

I have this enum:

enum VecP<'a> {
    Imut(&'a Vec<usize>),
    Mut(&'a mut Vec<usize>)
}

I want to pass it to a function and later to be able to use it again (or use it in a loop)
The function I want to pass it to accepts a VecP and I can't change it to accept a pointer.

If I were to do this:

let vp = VecP::Imut(&v);
func(vp); // ownership is given here and I can't use it anymore

The solution I've come up with is to do:

match vp {
    VecP::Mut(v) => {
        func(VecP::Mut(v)); // I don't loose ownership to v cuz it's a pointer
        vp = VecP::Mut(v); // because of the reassignment I can continue to use `vp`
    }
    VecP::Imut(v) => {
        func(VecP::Imut(v));
        vp = VecP::Imut(v);
    }
}

However this is somewhat tedious, (especailly if the func call is more complicated or there are more options to the enum) I was wondering if there is a better way, maybe something like a clone method?

Best I could think of is to write a macro to generate this code for me but that seems like overkill

playground

  • aside: [Using `&Vec` instead of `&[usize]` makes your structure less general and has a small additional overhead](https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-string-vec-or-box-as-a-function) – cafce25 Apr 25 '23 at 12:36
  • @cafce25 Ya thanks in my actual code I do that I just thought it might be a bit less confusing for the question if they have the same typ – Aharon Sambol Apr 25 '23 at 12:42

2 Answers2

3

One option is adding a method to VecP that does the matching and reconstruction for you:

enum VecP<'a> {
    Imut(&'a Vec<usize>),
    Mut(&'a mut Vec<usize>),
}

impl VecP<'_> {
    fn reborrow(&mut self) -> VecP {
        match *self {
            VecP::Imut(v) => VecP::Imut(v),
            VecP::Mut(ref mut v) => VecP::Mut(*v),
        }
    }
}

fn func(_: VecP) {
    // something
}

fn main() {
    let v = vec![1, 2, 3];
    let mut vp = VecP::Imut(&v);
    func(vp.reborrow());
    let _ = vp;
}

(Playground)

This hides the ugliness in the reborrow() method, so your actual function call doesn't look too bad. The code of reborrow() is a bit simpler than your version. You can get away with reborrowing the wrapped references rather than moving them out of the enum.

For what it's worth, the awkwardness seems to be caused by func() having the wrong interface. Getting the interface fixed would be my first attempt, but if there is no chance, you have to work around the problem.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
0

You could refactor your solution less tedious:

if let VecP::Imut(v) = vp {
    func(VecP::Imut(v));
}
if let VecP::Mut(v) = vp {
    func(VecP::Mut(v));
}

Playground

Kaplan
  • 2,572
  • 13
  • 14