【问题标题】:What's an idiomatic way to print an iterator separated by spaces in Rust?在 Rust 中打印由空格分隔的迭代器的惯用方法是什么?
【发布时间】:2016-04-29 15:09:48
【问题描述】:

我只想要从std::env::args() 获得的参数变量的空格分隔String,我一直在使用fold 函数创建,如下所示:

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

但是,这会在末尾创建一个多余的空间,这是不需要的。我尝试使用truncate 函数,但truncate 不返回String,只是修改了现有的String,而且这需要创建中间绑定才能使用String' s len() 调用来定义截断的 String 应该多长时间(我相信,由于 Rust 当前的词法借用规则,这本身需要一个中间绑定!)

【问题讨论】:

  • @Ferruccio 这只会产生一个前导空格,我只是按照我的方式进行操作,因为尾随空格通常是不可见的,而在格式中可以看到前导空格。我应该指定前导和尾随空格是不需要的。
  • 如果您愿意添加依赖项,intersperse 中有一个 intersperse 方法。我认为std 没有直接的方法。
  • 是的,当然,我应该意识到会发生这种情况。我之前遇到过这个问题(使用C#)。您需要检查accum 是否为空。我不确定这是否是有效的 Rust 语法,但我通常会这样做:accum + (if accum == "" {""} else {" "}) + &s
  • @Ferruccio 是的,这会起作用,看起来有点混乱,但没有什么太可怕的。不过,对于任何选择itertools 方法的人来说,请注意 - 在itertools 中有一个join 函数,它将所有元素连接到一个由指定分隔符分隔的String
  • 为什么所有这些都散布在 itertools 中(我经常看到)? Itertools 有实际的格式化方法,使用.join(" ") or .format_default(" ")

标签: rust


【解决方案1】:

在 Rust 中打印所有命令行参数的惯用方法是什么?

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

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

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

或者使用 Itertools 的 formatformat_with 更好:

use itertools::Itertools; // 0.8.0

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

我只想用空格分隔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());
}

或者

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

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

如果您使用 Itertools,则可以将上面的 format / format_with 示例与 format! 宏一起使用。

join 也很有用:

use itertools::Itertools; // 0.8.0

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

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

在其他情况下,您可能需要使用intersperse

use itertools::Itertools; // 0.8.0

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

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

请注意,这不像其他选择那样有效,因为每次迭代都会克隆 String

【讨论】:

  • 如果你把for循环放在if let里面,你就不需要使用fuse
  • 使用itertools,您可以直接使用std::env::args().join(" ")(感谢 OP 和 @bluss 在问题 cmets 中提供的提示)。
  • 对于intersperse 的例子,你不能直接调用.collect::<String>() 而不是折叠吗?
  • @Addison 是的!我猜我是用fold 从前面的示例中复制粘贴的,并且没有应用批判性思维。
【解决方案2】:

这是一个带有迭代器和零非标准库依赖项的解决方案

(性能方面,这在发布模式下大放异彩,开启了优化 [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());
}

【讨论】:

    【解决方案3】:

    这是一种替代方法

    我只想要从std::env::args() 获得的参数变量的空格分隔String

    fn args_string() -> String {
        let mut out = String::new();
        let mut sep = "";
        for arg in std::env::args() {
            out.push_str(sep);
            out.push_str(&*arg);
            sep = " ";
        }
        out
    }
    
    pub fn main() {
        println!("{}", args_string());
    }
    

    【讨论】:

      【解决方案4】:

      这是使用fold的版本

      fn join<I, T, D>(iter: I, separator: D) -> String
      where
          T: Display,
          D: Display,
          I: Iterator<Item = T>,
      {
          match iter.fold(None, |a:Option<String>, b| {
              Some(match a {
                  None => format!("{}", &b),
                  Some(mut a) => {
                      write!(a, "{}{}", separator, b).unwrap();
                      a
                  }
              })
          }) {
              None => String::new(),
              Some(rval) => rval,
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-04-23
        • 2016-05-25
        • 2021-03-14
        • 2016-03-27
        • 2011-06-01
        • 2020-12-23
        • 1970-01-01
        • 2022-08-18
        • 2019-12-26
        相关资源
        最近更新 更多