【问题标题】:What is the correct & idiomatic way to check if a string starts with a certain character in Rust?检查字符串是否以 Rust 中的某个字符开头的正确且惯用的方法是什么?
【发布时间】:2016-01-01 20:13:40
【问题描述】:

我想检查一个字符串是否以一些字符开头:

for line in lines_of_text.split("\n").collect::<Vec<_>>().iter() {
    let rendered = match line.char_at(0) {
        '#' => {
            // Heading
            Cyan.paint(*line).to_string()
        }
        '>' => {
            // Quotation
            White.paint(*line).to_string()
        }
        '-' => {
            // Inline list
            Green.paint(*line).to_string()
        }
        '`' => {
            // Code
            White.paint(*line).to_string()
        }
        _ => (*line).to_string(),
    };
    println!("{:?}", rendered);
}

我用过char_at,但是由于不稳定而报错。

main.rs:49:29: 49:39 error: use of unstable library feature 'str_char': frequently replaced by the chars() iterator, this method may be removed or possibly renamed in the future; it is normally replaced by chars/char_indices iterators or by getting the first char from a subslice (see issue #27754)
main.rs:49      let rendered = match line.char_at(0) {
                                      ^~~~~~~~~~

我目前正在使用 Rust 1.5

【问题讨论】:

    标签: string rust


    【解决方案1】:

    错误消息提供了有用的提示:

    经常被chars() 迭代器替换,这个方法将来可能会被删除或可能重命名;它通常由chars/char_indices 迭代器或从子切片中获取第一个字符替换(参见issue #27754

    1. 我们可以按照错误文本:

      for line in lines_of_text.split("\n") {
          match line.chars().next() {
              Some('#') => println!("Heading"),
              Some('>') => println!("Quotation"),
              Some('-') => println!("Inline list"),
              Some('`') => println!("Code"),
              Some(_)   => println!("Other"),
              None      => println!("Empty string"),
          };
      }
      

      请注意,这会暴露您未处理的错误情况!如果没有第一个字符怎么办?

    2. 我们可以切片字符串,然后在字符串切片上进行模式匹配:

      for line in lines_of_text.split("\n") {
          match &line[..1] {
              "#" => println!("Heading"),
              ">" => println!("Quotation"),
              "-" => println!("Inline list"),
              "`" => println!("Code"),
              _   => println!("Other")
          };
      }
      

      对字符串进行切片操作按字节,因此如果您的第一个字符不完全是 1 个字节(也称为 ASCII 字符),这将导致恐慌。如果字符串为空,它也会恐慌。您可以选择避免这些恐慌:

      for line in lines_of_text.split("\n") {
          match line.get(..1) {
              Some("#") => println!("Heading"),
              Some(">") => println!("Quotation"),
              Some("-") => println!("Inline list"),
              Some("`") => println!("Code"),
              _ => println!("Other"),
          };
      }
      
    3. 我们可以使用与您的问题陈述直接匹配的方法str::starts_with

      for line in lines_of_text.split("\n") {
          if line.starts_with('#')      { println!("Heading") }
          else if line.starts_with('>') { println!("Quotation") }
          else if line.starts_with('-') { println!("Inline list") }
          else if line.starts_with('`') { println!("Code") }
          else                          { println!("Other") }
      }
      

      请注意,如果字符串为空或第一个字符不是 ASCII,此解决方案不会出现恐慌。出于这些原因,我可能会选择此解决方案。将 if 主体与 if 语句放在同一行不是正常的 Rust 风格,但我这样说是为了使其与其他示例保持一致。您应该看看如何将它们分成不同的行。


    顺便说一句,您不需要collect::&lt;Vec&lt;_&gt;&gt;().iter(),这只是效率低下。没有理由使用迭代器,从中构建一个向量,然后遍历该向量。只需使用原始迭代器即可。

    【讨论】:

    • 是的,我认为收集到矢量也效率低下。我不知道 Split 和 iter 是同一个迭代器。请问,您的解决方案哪个更快?还是它们的速度大致相同?
    • @rilut 你可以问,但我不知道答案^_^。也许有人会插话,但您也可以在您的应用程序中进行一些性能测试并确定。我可能它们都是一样的。
    • 每个人都很困惑,但至少现在答案是完美无缺的:)
    • @rilut 无论如何它都不是相同的迭代器,但它完全是一个迭代器
    • @bluss 是的,我就是这个意思:)
    猜你喜欢
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-07
    • 2023-01-01
    • 2011-05-04
    相关资源
    最近更新 更多