Benefits of converting Vec to Box<[T]> / Rc<[T]>?

Hi folks,

I have a function that takes a slice as an argument and returns a struct with a couple of fields. One of those fields is a vector with elements that are another struct. Those elements are built using try_fold from the slice argument.

I was thinking, if the function takes a slice, it could also store a slice. Of course, the struct owns the elements so I'd need to convert it from Vec using items.into_boxed_slice() to:

struct Parent {
    childs: Box<[Child]>,
}

or using Rc::from(items.as_slice()) to:

struct Parent {
    childs: Rc<[Child]>,
}

Is there a benefit in converting it? I won't mutate the struct/any fields of the struct. I don't plan to clone it but I might need to in the future.

Thank you.

I think there is a benefit to using the most constrained type, to make it clear that it is constrained. From that viewpoint, the choice of Vec/Box/Rc depends on whether you need the features of each type. Vec can changed in length. Rc can be shared (within a thread). Box has neither of those features.

If you're not sure, just keep using the Vec<T> for now. The different isn't substantial.

Using Box<[T]> makes your Parent struct slightly smaller -- 2 pointers instead of 3 -- at the cost of potentially (probably, if the Vec was built by pushing) needing extra reallocation and copying. If you build it once, then keep it around for a long time that can be worth it, but if it's lives for not very long you're usually better off leaving it as a Vec. (And if you continue to push things over time, you're definitely better off leaving it as a Vec.)

2 Likes

You can just store the Vec. The boxed slice might be better since it's one pointer smaller, with the downside that it might have to allocate, but you definitely don't need to convert it. If you need to minimize the size of this struct, you may even consider Box<Vec<Child>> or Box<Box<[Child]>>.

Since you have an owned Vec, you would do Rc::from(items). This is slightly cheaper since it doesn't need to clone the items, although it still needs to allocate. If reallocating is too costly but you still want cheap clones, you might even do Rc<Vec<Child>>.

Yes, using .push() inside try_fold

I won't mutate the Vec or the struct.

Thank you.

I didn't realize that the convertion is costly - but of course nothing is free of CPU time ;-). I guess the best is just to keep it as Vec. Thank you all!