# Idea: \`clone\_with\_capacity\`

**URL:** <https://internals.rust-lang.org/t/idea-clone-with-capacity/16646>\
**Category:** libs\
**Created:** [May 17, 2022, 4:37pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646 "2022-05-17T16:37:34Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nian](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nian/32/9393_2.png) [@Nian](https://internals.rust-lang.org/u/Nian)\
**Post date:** [May 17, 2022, 4:37pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/1 "2022-05-17T16:37:34Z")

</div>

Cloning `Vec` will trim the capacity for space optimization, but in some cases pushing something to cloned `Vec` are necessary. For example, when I build `Vec<PathBuf>` to copy thousands of files to another directory and rename each file to another name(mostly longer than the origin), the underlying reallocation is almost inevitable, resulting in much time waste. I'm not sure if it is worth doing so; it is not that common after all. It applies to many other containers, of which `Vec` is just one case for convenience.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [May 17, 2022, 4:49pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/2 "2022-05-17T16:49:52Z")

</div>

You can call `Vec::with_capacity` and then `vec.extend(&other)`, but a vector of thousands isn't very big in the first place. If anything, I suspect you'd hit more reallocation activity while changing each `PathBuf`, but even that will be dwarfed by the syscalls to make the actual filesystem changes.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 17, 2022, 4:53pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/3 "2022-05-17T16:53:16Z")

</div>

> [@cuviper](#):
>
> and then `vec.extend(&other)`

For a type like `PathBuf`, you’d need `vec.extend_from_slice(&other)` because it’s not `Copy`. I’m now noticing the documentation of `Vec::extend_from_slice` misses this difference.

---

<div class="post-metadata">

**Author:** ![Nian](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nian/32/9393_2.png) [@Nian](https://internals.rust-lang.org/u/Nian)\
**Post date:** [May 17, 2022, 4:56pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/4 "2022-05-17T16:56:15Z")

</div>

Yes, I mean the reallocation of each `PathBuf`, not `Vec<PathBuf>`. Thanks for your reminding

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [May 17, 2022, 5:02pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/5 "2022-05-17T17:02:53Z")

</div>

You can also use something like `let mut new_paths = Vec::with_capacity(old_paths.capacity()); new_paths.clone_from(&old_paths);` to clone `old_paths` into `new_paths` while keeping the same capacity. `clone_from` is a method on `Clone` so it works on all `Clone` types. However most types use the default implementation of `*self = other.clone();` which won't reuse any memory. `Vec` has an implementation of `clone_from` which reuses memory though.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [May 17, 2022, 5:19pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/6 "2022-05-17T17:19:57Z")

</div>

In addition to its own capacity, `Vec::clone_from` uses `clone_from` on each item. `PathBuf` also optimizes `clone_from`, forwarding multiple layers down to _its_ inner `Vec`. So you could do something like:

```rust
let buffers = iter::repeat_with(|| PathBuf::with_capacity(new_path_capacity));
let mut new_paths = Vec::from_iter(buffers.take(old_paths.len()));
new_paths.clone_from(&old_paths);

```

Or you can deal with each rename on the fly:

```rust
old_paths.iter().map(|path| {
    let new_capacity = todo!("calculate from path");
    let mut rename = PathBuf::with_capacity(new_capacity);
    rename.clone_from(path);
    // modify further...
    rename
}).collect::<Vec<_>>();
```

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [May 17, 2022, 6:51pm UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/7 "2022-05-17T18:51:44Z")

</div>

> [@Nian](#):
>
> and rename each file to another name(mostly longer than the origin)

This makes me wonder if it's better done as an iterator-like thing instead, since `collect` can get the capacity right.

This is like how `my_str.to_owned() + other_str` also has the problem -- but the fix isn't `.to_owned_with_capacity()`, but to instead use `[my_str, other_str].concat()`, [which](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.concat) allocates the correct amount of space up front

---

<div class="post-metadata">

**Author:** ![Nian](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nian/32/9393_2.png) [@Nian](https://internals.rust-lang.org/u/Nian)\
**Post date:** [May 18, 2022, 1:58am UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/8 "2022-05-18T01:58:46Z")

</div>

Thanks for the alternatives. By the way, I find that the function I propose relies on the fact that the old `Clone` object must have some extra capacity, which is sometimes unnecessary.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [August 16, 2022, 1:59am UTC](https://internals.rust-lang.org/t/idea-clone-with-capacity/16646/9 "2022-08-16T01:59:22Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
