【问题标题】:How do I join a char vector in Rust如何在 Rust 中加入 char 向量
【发布时间】:2021-12-31 03:33:31
【问题描述】:

我正在做 rustlings 练习,我试着用这个来做一个大写函数。但是连接部分不起作用。它说:

“结构Vec<char>存在方法join,但不满足其特征边界 不满足以下特征界限: <[char] as Join<_>>::Output = _"

我不知道是什么意思。加入 char 向量的正确方法是什么?

pub fn capitalize_first(input: &str) -> String {
    let mut c = input.chars();
    match c.next() {
        None => String::new(),
        Some(first) => {
            let upper = first.to_ascii_uppercase();
            let mut v = c.collect::<Vec<char>>();
            v[0] = upper;
            v.join("")
        },
    }
}

【问题讨论】:

  • 请注意,此代码也存在逻辑错误,因为它删除了原始字符串的第二个字符 - play.rust-lang.org/…
  • 还有一个选项可以使用without一个向量,但是你需要with一个向量的解决方案。
  • 确实如此。我没有注意到收集迭代器会收集它的其余部分,即尚未迭代的部分。我以为它会从一开始就收集它。谢谢

标签: string rust iterator char


【解决方案1】:

要回答您的问题,从 vec 字符中获取字符串的最佳方法是迭代和收集:

 let my_string = my_char_vec.iter().collect();

但是您的代码中还有其他问题:

  1. 您使用第一个字符来检查字符串是否为空,然后从迭代的其余部分构建一个字符串,并让第一个字符替换该字符串的第一个字符...丢失此字符这是初始 str 的第二个
  2. 您正在构建一个无用的 vec 并再次进行迭代。这些是您不需要的昂贵步骤

您可以通过调整代码直接从迭代写入字符串来解决这些问题:

pub fn capitalize_first(input: &str) -> String {
    let mut chars = input.chars();
    let mut string = String::new();
    if let Some(first) = chars.next() {
        string.push(first.to_ascii_uppercase());
        for c in chars {
            string.push(c);
        }
    }
    string
}

请注意,您正在使用专用于 ASCII 字符的函数。当您确定您只处理 ASCII 时,这很好,但如果您想要在国际环境中工作的东西,您想使用更通用的 to_uppercase。 由于一个unicode大写字符可能是几个字符,代码稍微复杂一点:

pub fn capitalize_first(input: &str) -> String {
    let mut chars = input.chars();
    let mut string = String::new();
    if let Some(first) = chars.next() {
        let first = first.to_uppercase();
        for c in first {
            string.push(c);
        }
        for c in chars {
            string.push(c);
        }
    }
    string
}

如果您确定可以使用to_ascii_upercase,那么还有另一种解决方案。 因为 ASCII 字符在小写和大写中只有一个字节,您可以在 UTF8 字符串中原地更改它们:

pub fn capitalize_first(input: &str) -> String {
    let mut string = input.to_string();
    if !string.is_empty() {
        string[..1].make_ascii_uppercase();
    }
    string
}

第二种方法可以用于零分配的可变字符串。但如果第一个字符不是一个字节长,它会恐慌。

【讨论】:

  • 我不确定 OP 是否知道,如果第一个字符不是字符边界分别不是 ascii 字符,则程序将失败。
  • @Kaplan 是的,我会对此发表更多评论
  • 谢谢。这是一个非常完整的解决方案:D
【解决方案2】:

join 方法的返回类型中有一个约束,char 类型不满足,因为它没有静态生命周期:

pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
    where
        Self: Join<Separator>,
    {
        Join::join(self, sep)
    }

您应该改用String::from_iter

pub fn capitalize_first(input: &str) -> String {
  let mut c = input.chars();
  match c.next() {
      None => String::new(),
      Some(first) => {
          let upper = first.to_ascii_uppercase();
          let mut v = c.collect::<Vec<char>>();
          v[0] = upper;
          String::from_iter(v)
      },
  }
}

【讨论】:

  • .join 不起作用的原因是因为加入String requires 元素来实现Borrow&lt;str&gt;,而char 没有。而不是因为一些静态的生命周期限制。
  • @kmdreko,哦,谢谢你的澄清!我当时看错了错误信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多