'Why is Rust pushing new line into String when pushing optional character? [duplicate]

I am trying an exercise from the end of Chapter 8 in The Rust Programming Language to translate words into pig latin. Unfortunately, I am having a problem where my algorithm inserts a new line before the ending.

For example, the word "rust" is translated as follows:

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/pig_latin`
Please type a word.
rust
ust
ray

My code is as follows:

use std::io;

fn main() {
    println!("Please type a word.");

    let mut word = String::new();
   
    io::stdin()
        .read_line(&mut word)
        .expect("Failed to read line");

    let mut translation = String::new();
    let mut first_letter: Option<char> = None;

    let mut first_run = true;
    for c in word.chars() {
        if first_run {
            first_run = false;

            match c {
                'a' => translation.push('a'),
                'e' => translation.push('e'),
                'i' => translation.push('i'),
                'o' => translation.push('o'),
                'u' => translation.push('u'),
                _ => first_letter = Some(c),
            }
        } else {
            translation.push(c);
        }
    }

    if let Some(letter) = first_letter {
        translation.push(letter);
        translation.push_str("ay");
    } else {
        translation.push_str("ay");
    }

    println!("{}", translation);
}

What am I doing wrong?



Solution 1:[1]

As was pointed out by @eggyal in the comments, "read_line() includes the newline character at the end of the input word." So, my for loop didn't end without pushing that newline character onto my translation. To solve this problem, I just looped of a slice of my word minus the last character and it worked.

My new code is as follows:

use std::io;

fn main() {
    println!("Please type a word.");

    let mut word = String::new();
   
    io::stdin()
        .read_line(&mut word)
        .expect("Failed to read line");

    let mut translation = String::new();
    let mut first_letter: Option<char> = None;

    let mut first_run = true;

    // for c in word[..word.len() - 1].chars() {
    for c in word.trim().chars() { // suggested by @Cerberus
        if first_run {
            first_run = false;

            match c {
                'a' => translation.push('a'),
                'e' => translation.push('e'),
                'i' => translation.push('i'),
                'o' => translation.push('o'),
                'u' => translation.push('u'),
                _ => first_letter = Some(c),
            }
        } else {
            translation.push(c);
        }
    }

    if let Some(letter) = first_letter {
        translation.push('-');
        translation.push(letter);
        translation.push_str("ay");
    } else {
        translation.push('-');
        translation.push_str("hay");
    }

    println!("{}", translation);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1