【问题标题】:In Rust, what's the idiomatic way to split a &str into an iterator of &strs of one character each?在 Rust 中,将 &str 拆分为 &strs 每个字符的迭代器的惯用方法是什么?
【发布时间】:2020-04-23 03:35:38
【问题描述】:

如果我想将&str"aeiou" 一样转换为大致相当于["a", "e", "i", "o", "u"].iter() 的迭代器,那么最惯用的方法是什么?

我尝试过"aeiou".split(""),这对我来说似乎是惯用的,但我在开头和结尾都空了&strs。

我尝试过使用"aeiou".chars(),但是从那里尝试将chars 变成&strs 时变得非常丑陋和笨拙。

目前,我只是输入了["a", "e", "i", "o", "u"].iter(),但必须有更简单、更惯用的方式。

对于上下文,我最终将遍历每个值并将其传递到类似string.matches(vowel).count() 的内容中。

这是我的整体代码。也许我在其他地方误入歧途。

fn string_list_item_count<'a, I>(string: &str, list: I) -> usize
where
    I: IntoIterator<Item = &'a str>,
{
    let mut num_instances = 0;

    for item in list {
        num_instances += string.matches(item).count();
    }

    num_instances
}

// snip

string_list_item_count(string, vec!["a", "e", "i", "o", "u"])

// snip

如果我能让string_list_item_count 接受迭代器内的std::str::pattern::Pattern 特征,我认为这将使该函数接受&amp;strchar 的迭代器,但Pattern 特征是一个夜间不稳定的API,并且我试图避免使用这些。

【问题讨论】:

  • 这能回答你的问题吗? How do I convert a string to a list of chars?
  • 不,我希望基本上做相反的事情。将 chars 的迭代器转换为 &strs 的迭代器。
  • 您如何在问题的上下文中定义角色? ASCII 字符? Unicode代码点?字形簇? ...?
  • 这很好。这就是为什么我希望 Pattern 是稳定的,所以我不必指定一个类型。我希望我可以使用 .matches 接受的任何东西。 .matches 是稳定的,但它的基本特征却不是,这对我来说有点奇怪。

标签: string generics rust iterator traits


【解决方案1】:

闭包也可以作为Pattern

fn main() {
    let vowels = "aeiou";
    let s = "the quick brown fox jumps over the lazy dog";
    let count = string_item_count(s, vowels);
    dbg!(count);
}

fn string_item_count(string: &str, pat: &str) -> usize {
    let pred = |c| pat.contains(c);
    string.matches(pred).count()
}

【讨论】:

    【解决方案2】:

    我会将str::split 与空字符串一起使用,然后使用Iterator::filter 删除任何空字符串:

    fn string_chars(s: &str) -> impl Iterator<Item = &str> {
        s.split("").filter(|s| !s.is_empty())
    }
    
    fn main() {
        assert_eq!(
            string_chars("aeiou").collect::<Vec<_>>(),
            ["a", "e", "i", "o", "u"],
        );
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用split_terminator 而不是split 来跳过迭代器末尾的空字符串。另外,如果你skip迭代器的第一个元素,你会得到你想要的结果:

      let iterator = "aeiou".split_terminator("").skip(1);
      println!("{:?}", iterator.collect::<Vec<_>>());
      

      输出:

      ["a", "e", "i", "o", "u"]
      

      【讨论】:

      • 嗯。那很有意思。它仍然感觉有点糟糕,只是因为它比输入 vec 的字符更多。 ?
      • 是的。但它确实适用于更长的字符串
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-18
      • 2016-05-25
      • 2011-06-02
      • 2021-03-14
      • 2010-12-21
      • 1970-01-01
      • 2021-01-18
      相关资源
      最近更新 更多