将Vec<String>作为IntoIterator<&'a str>传递

7
我有一个函数,它应该从单词列表中随机选择单词:
pub fn random_words<'a, I, R>(rng: &mut R, n: usize, words: I) -> Vec<&'a str>
where
    I: IntoIterator<Item = &'a str>,
    R: rand::Rng,
{
    rand::sample(rng, words.into_iter(), n)
}

假设这是一个合理的签名:由于函数本身并不需要字符串本身,因此使用引用工作比使用完整的String更高效。

我应该如何优雅、高效地传递程序从文件中读取的单词的Vec<String>到这个函数中? 我已经做到了这一步:

extern crate rand;

fn main() {
    let mut rng = rand::thread_rng();
    let wordlist: Vec<String> = vec!["a".to_string(), "b".to_string()];

    let words = random_words(&mut rng, 4, wordlist.iter().map(|s| s.as_ref()));
}

这种方式正确吗?我能否不显式地遍历单词列表来获取引用而进行编写?


处理引用比使用完整的String更有效,也许是这样,也许不是;这实际上更取决于您如何使用字符串。如果您稍后将&str转换为String并丢弃Vec<String>,那么最好直接对String进行采样。如果您确实需要对项目进行引用,我可能会编写类似于您的代码:rand::sample(rng, words.iter().map(AsRef::as_ref), 4) - Shepmaster
1
在我看来,你的 random_words 函数没有任何有用的作用,你应该直接使用 rand::sample - starblue
1个回答

10

你可以将通用函数更改为接受任何可以转换为&str的内容,而不是让它接受产生&str的迭代器:

您可以更改通用函数以接受任何可转换为&str的内容,而不是让其接受生成&str的迭代器。

pub fn random_words<'a, I, R, J>(rng: &mut R, n: usize, words: I) -> Vec<&'a str>
where
    I: IntoIterator<Item = &'a J>,
    J: AsRef<str> + 'a,
    R: rand::Rng,
{
    rand::sample(rng, words.into_iter().map(AsRef::as_ref), n)
}
let words: Vec<&str> = random_words(&mut rng, 4, &wordlist);

该书甚至专门有一章节讲述了这个主题。


那么实现会是什么样子呢?我尝试了各种方法,但是我无法通过借用检查器来获取我的问题中的任何主体变量。 - user355252
你尝试过类似 rand::sample(rng, words.map(AsRef::as_ref), n) 这样的东西吗? - oli_obk
很遗憾,那是一种类型错误。非常抱歉,但我对Rust还很陌生,需要很多指导。 - user355252
是的,问题在于“Item”也需要是引用。我更新了代码以及“rand::sample”调用。 - oli_obk
非常感谢!现在已经编译成功了,我需要两天时间来理解发生了什么 ;) - user355252

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接