Get a random character from a string and append to another string

后端 未结 1 318
有刺的猬
有刺的猬 2021-01-24 15:56

I\'m trying to write the Rust equivalent of the following C++ code:

result += consonants[rand() % consonants.length()];
<         


        
相关标签:
1条回答
  • 2021-01-24 16:36

    A few things:

    • You don't need to use format!() here. There is String::push() which appends a single char.

    • There is also the rand::sample() function which can randomly choose multiple elements from an iterator. This looks like the perfect fit!

    So let's see how this fits together! I created three different versions for different use cases.

    1. Unicode string (the general case)

    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 --+
    

    (Playground)

    We sample only one element from the iterator and immediately push it to the string. Still not as short as with C's rand(), but please note that rand() is considered harmful for any kind of serious use! Using C++'s <random> header is a lot better, but will require a little bit more code, too. Additionally, your C version can't handle multi-byte characters (e.g. UTF-8 encoding), while the Rust version has full UTF-8 support.

    2. ASCII string

    However, if you only want to have a string with English consonants, then UTF-8 is not needed and we can make use of O(1) indexing, by using a byte slice:

    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` ^^^^
    

    (Playground)

    3. Collection of characters with Unicode support

    As mentioned in the comments, you probably just want a collection of characters ("consonants"). This means, we don't have to use a string, but rather an array of chars. So here is one last version which does have UTF-8 support and avoids O(n) indexing:

    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());
    

    (Playground)

    0 讨论(0)
提交回复
热议问题