# Optimize \`std::env::args\_os().collect::\<Vec\<\_\>\>()\`

**URL:** <https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644>\
**Category:** libs\
**Created:** [October 22, 2025, 8:06am UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644 "2025-10-22T08:06:29Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![TauYip](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tauyip/32/13719_2.png) [@TauYip](https://internals.rust-lang.org/u/TauYip)\
**Post date:** [October 22, 2025, 8:06am UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/1 "2025-10-22T08:06:29Z")

</div>

Sometimes I want to cache the command line arguments,

so I would write `args_os().collect::<Vec<_>>()`.

But recently I found that `.collect()` causes further allocation,

while immediate converting `vec::IntoIter` to `Vec` requires no allocation.

If `ArgsOs` is no more than `vec::IntoIter`, converting `ArgsOs` to `Vec` should be zero-cost.

But a wrapper of `vec::IntoIter` just can't trigger `SpecFromIter<T, vec::IntoIter<T>>`.

Can we add some support to eliminate that overhead?

For example, add a method `ArgsOs::into_inner` to allow `args_os().into_inner().collect::<Vec<_>>` to be zero-cost,

or add something like `ArgsOs::into_vec`, etc.

---

<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:** [October 22, 2025, 8:41am UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/2 "2025-10-22T08:41:01Z")

</div>

I think the implementation of `env::args_os()` on most OSes could be made to not allocate a `Vec` at all and instead convert the OS argument representation to `OsString` elements on the fly.

---

<div class="post-metadata">

**Author:** ![chrisd](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chrisd/32/7232_2.png) [@chrisd](https://internals.rust-lang.org/u/chrisd)\
**Post date:** [October 22, 2025, 1:53pm UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/3 "2025-10-22T13:53:53Z")

</div>

Though that is potentially problematic because argv can be modified during runtime (some argument parsers do this). Though admittedly this is technically also a problem at the minute but doing it all at once at least makes it less likely.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [October 22, 2025, 4:09pm UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/4 "2025-10-22T16:09:26Z")

</div>

> [@TauYip](#):
>
> But recently I found that `.collect()` causes further allocation

Note that this isn't true in this case, but good luck figuring that out without a debugger:

> **[spec\_from\_iter.rs - source](https://doc.rust-lang.org/src/alloc/vec/spec_from_iter.rs.html#40-58)**
>
> Source of the Rust file \`library/alloc/src/vec/spec\_from\_iter.rs\`.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jrose/32/9591_2.png) [@jrose](https://internals.rust-lang.org/u/jrose)\
**Post date:** [October 22, 2025, 4:17pm UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/5 "2025-10-22T16:17:54Z")

</div>

Also, I know Rust makes it easy to pay attention and see where all your allocations are, but 90% of programs will have less than 40 command line arguments, which means your entire Vec (as opposed to the strings inside it) will be smaller than 1KiB, a size that’s about 1% of a 3.5" floppy disk from the 80s and won’t even show up in your used memory stats on an operating system from the last ten years. As long as you’re not doing this over and over, you really don’t need to worry about the memory or CPU cost of one extra allocation.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [October 22, 2025, 6:43pm UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/6 "2025-10-22T18:43:56Z")

</div>

There would (edit: hypothetically!) be value in a non-allocating version if it allowed functionality to be moved into core. `a_vec.into_iter().collect()` being cheap _is_ a pattern that perhaps could be better highlighted, but the status quo is also pretty reasonable from my perspective.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [October 22, 2025, 10:16pm UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/7 "2025-10-22T22:16:52Z")

</div>

`env::args_os()` cannot be in `core` because it retrieves information provided by the operating system. `core` is the subset of the standard library that does not assume any particular operating system (nor does it assume the lack of one).

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [October 22, 2025, 10:43pm UTC](https://internals.rust-lang.org/t/optimize-std-args-os-collect-vec/23644/8 "2025-10-22T22:43:17Z")

</div>

The datastructures depended upon by OS related operations do not necessarily need to live outside of `core`, and can be useful outside of it to represent analogous datastructures without an operating system. _Admittedly I don't think there's much demand for it._
