我试图写下以下C ++代码的Rust等价物:
result += consonants[rand() % consonants.length()];
它意味着从字符串consonants
中取一个随机字符并将其附加到字符串result
。
我似乎找到了一个有效的Rust等效物,但它至少可以说是怪异的。什么是更惯用的等价物?
format!("{}{}", result, consonants.chars().nth(rand::thread_rng().gen_range(1, consonants.chars().count())).unwrap().to_string());
答案 0 :(得分:7)
一些事情:
您不需要在此处使用format!()
。有String::push()
附加一个字符。
还有rand::sample()
函数可以从迭代器中随机选择多个元素。这看起来非常合适!
让我们看看它是如何组合在一起的!我为不同的用例创建了三个不同的版本。
let consonants = "bcdfghjklmnpqrstvwxyz";
let mut result = String::new();
result.push(rand::sample(&mut rand::thread_rng(), consonants.chars(), 1)[0]);
// | |
// sample one element from the iterator --+ |
// |
// get the first element from the returned vector --+
我们只从迭代器中采样一个元素并立即将其推送到字符串。仍然没有C&rand()
那么简短,但请注意rand()
is considered harmful用于任何严重用途!使用C ++的<random>
标头要好得多,但也需要更多的代码。此外,您的C版本无法处理多字节字符(例如UTF-8编码),而Rust版本则支持完整的UTF-8。
但是,如果你只想要一个带有英语辅音的字符串,那么就不需要UTF-8了,我们可以使用字节切片来使用O(1)索引:
use rand::{thread_rng, Rng};
let consonants = b"bcdfghjklmnpqrstvwxyz";
let mut result = String::new();
result.push(thread_rng().choose(consonants).cloned().unwrap().into());
// convert Option<&u8> into Option<u8> ^^^^^^
// unwrap, because we know `consonants` is not empty ^^^^^^
// convert `u8` into `char` ^^^^
正如评论中所提到的,你可能只想要一组字符(&#34;辅音&#34;)。这意味着,我们不必使用字符串,而是使用chars
的数组。所以这是最后一个版本,它有UTF-8支持和避免O(n)索引:
use rand::{thread_rng, Rng};
// If you need to avoid the heap allocation here, you can create a static
// array like this: let consonants = ['b', 'c', 'd', ...];
let consonants: Vec<_> = "bcdfghjklmnpqrstvwxyz".chars().collect();
let mut result = String::new();
result.push(*thread_rng().choose(&consonants).unwrap());