What's an idiomatic way to print an iterator separated by spaces in Rust?

I just want a space separated String of the argument variables obtained from std::env::args(), which I've been creating using the fold function like this:

std::env::args()
    .fold("".to_string(), |accum, s| accum + &s + " ")

However this creates an extra space at the end which is unwanted. I tried using the truncate function, but truncate doesn't return a String, just modifies the existing String, and also this would require the creation of an intermediate binding in order to use the String's len() call to define how long the truncated String should be (which itself would require an intermediate binding due to Rust's current lexical borrowing rules I believe!)


What's an idiomatic way to print all command line arguments in Rust?

fn main() {
    let mut args = std::env::args();

    if let Some(arg) = args.next() {
        print!("{}", arg);

        for arg in args {
            print!(" {}", arg);
        }
    }
}

Or better with Itertools' format or format_with:

use itertools::Itertools; // 0.8.0

fn main() {
    println!("{}", std::env::args().format(" "));
}

I just want a space separated String

fn args() -> String {
    let mut result = String::new();
    let mut args = std::env::args();

    if let Some(arg) = args.next() {
        result.push_str(&arg);

        for arg in args {
            result.push(' ');
            result.push_str(&arg);
        }
    }

    result
}

fn main() {
    println!("{}", args());
}

Or

fn args() -> String {
    let mut result = std::env::args().fold(String::new(), |s, arg| s + &arg + " ");
    result.pop();
    result
}

fn main() {
    println!("{}", args());
}

If you use Itertools, you can use the format / format_with examples above with the format! macro.

join is also useful:

use itertools::Itertools; // 0.8.0

fn args() -> String {
    std::env::args().join(" ")
}

fn main() {
    println!("{}", args());
}

In other cases, you may want to use intersperse:

use itertools::Itertools; // 0.8.0

fn args() -> String {
    std::env::args().intersperse(" ".to_string()).collect()
}

fn main() {
    println!("{}", args());
}

Note this isn't as efficient as other choices as a String is cloned for each iteration.


Here's a solution with iterators, and zero non-stdlib dependencies

(performance wise, this shines in release mode, with optimizations turned on [playground])

use std::iter::once;

fn join_iter<T>(
    mut iter: impl Iterator<Item = T>,
    sep: impl Fn(&T) -> T,
) -> impl Iterator<Item = T> {
    iter.next()
        .into_iter()
        .chain(iter.flat_map(move |s| once(sep(&s)).chain(once(s))))
}

fn examples() {
    let iter = [1, 3, 5, 7, 9].iter().cloned();
    println!("{:?}", join_iter(iter, |v| v - 1).collect::<Vec<_>>());
    // [1, 2, 3, 4, 5, 6, 7, 8, 9]

    let iter = ["Hello", "World"].iter().cloned();
    let sep = ", ";
    println!("{:?}", join_iter(iter, |_| sep).collect::<String>());
    // "Hello, World"
}

fn args() -> String {
    join_iter(std::env::args(), |_| " ".to_string()).collect()
}

fn main() {
    examples();

    println!("{}", args());
}