Search code examples
stringloopsruststring-concatenation

Concatenate strings with spaces using only conditionals inside of a for-loop body


I'm doing Rust Koans and am stuck on a this question:

#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let space: &str = " ";
    let mut sentence: String = String::new();
    for word in words.iter() {
        // __
    }

    println!("{:?}", sentence);
    assert!(sentence == "I love Rust".to_string());
}

I know I need to concatenate the string but this will fail:

#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let mut sentence: String = String::new();
    for word in words.iter() {
        sentence.push_str(word);
    }

    println!("{:?}", sentence); // "ILoveRust"
    assert!(sentence == "I love Rust".to_string());
}

I can add a space after each iteration:

#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let space: &str = " ";
    let mut sentence: String = String::new();
    for word in words.iter() {
        sentence.push_str(word);
        sentence.push_str(space);
    }

    println!("{:?}", sentence); // "I Love Rust "
    assert!(sentence == "I love Rust".to_string());
}

This will also fail because the final iteration will add a space.

I guess I could write a conditional if we are on the last iteration, but I'm struggling to get the syntax correct. Moreover, I feel like there is a much better solution for all of this and I just can't figure out syntax.

How can I make the assertion above pass with a conditional in the loop to not add the space on the last iteration?


Solution

  • You can use slice::join:

    #[test]
    fn for_loops_two() {
        let words: [&'static str; 3] = ["I", "love", "Rust"];
    
        let sentence = words.join(" ");
    
        assert!(sentence == "I love Rust".to_string());
    }
    

    A note on the linked SliceConcatExt trait: it's listed as unstable on the docs, but the methods are stable - the above compiles just fine under the current stable edition of Rust.

    If you'd rather stick to the constraints of the koan and use a for-loop, you can either use an if as you suggest (figuring out whether you're at the end using enumerate), or pop the last space from the end of the string:

    #[test]
    fn for_loops_two_with_len_check() {
        let words: [&'static str; 3] = ["I", "love", "Rust"];
        const SPACE: char = ' ';
        let number_of_words = words.len();
        let mut sentence = String::new();
    
        for (i, word) in words.iter().enumerate() {
            sentence.push_str(word);
            if i < number_of_words-1 {
                sentence.push(SPACE);
            }
        }
    
        assert!(sentence == "I love Rust".to_string());
    }
    
    
    #[test]
    fn for_loops_two_with_pop() {
        let words: [&'static str; 3] = ["I", "love", "Rust"];
        const SPACE: char = ' ';
        let mut sentence = String::new();
    
        for word in words.iter() {
            sentence.push_str(word);
            sentence.push(SPACE);
        }
        let _ = sentence.pop();
    
        assert!(sentence == "I love Rust".to_string());
    }