Twelve days of christmas, my attempt

I just started learning Rust and while reading the book https://doc.rust-lang.org/book/ I decided to make an attempt at the challenge of writing a program to generate the lyrics of Twelve Days of Christmas.

At the beginning I wrote everything using String:new() to create my strings, but when I read the part with slices and stack and heap, I wondered if I could write it differently.

I chose to implement something to generate the lyrics from John Denver and The Muppets.

I'd like to have feedbacks from more experienced Rustaceans about what would be better about my code in general and about String vs &'static str

fn day_string(day_nbr: i32) -> &'static str {
    match day_nbr {
        1 => &"first",
        2 => &"second",
        3 => &"third",
        4 => &"fourth",
        5 => &"fifth",
        6 => &"sixth",
        7 => &"seventh",
        8 => &"eighth",
        9 => &"ninth",
        10 => &"tenth",
        11 => &"eleventh",
        12 => &"twelfth",
        _ => panic!("day_nbr not supported."),
    }
}

fn get_giver_phrase(day_nbr: i32) -> &'static str {
    if day_nbr == 9 {
        &"Me me me me me me\n"
    } else {
        &"My true love gave to me\n"
    }
}

fn gift(curr_day: i32, gift_nbr: i32) -> String {
    match gift_nbr {
        1 => {
            if curr_day == 1 {
                String::from("A Partridge in a Pear Tree\n")
            } else {
                String::from("And a Partridge in a Pear Tree\n")
            }
        }
        2 => String::from("Two Turtle Doves\n"),
        3 => String::from("Three French Hens\n"),
        4 => String::from("Four Calling Birds\n"),
        5 => {
            if curr_day < 9 {
                String::from("Five gold rings\n")
            } else {
                String::from("Five gold rings, badam-pam-pam\n")
            }
        }
        6 => String::from("Six Geese a Laying\n"),
        7 => String::from("Seven Swans a Swimming\n"),
        8 => String::from("Eight Maids a Milking\n"),
        9 => String::from("Nine Ladies Dancing\n"),
        10 => String::from("Ten Lords a Leaping\n"),
        11 => String::from("Eleven Pipers Piping\n"),
        12 => String::from("12 Drummers Drumming\n"),
        _ => String::from(""),
    }
}

fn main() {
    println!("TWELVE DAYS OF CHRISTMAS:\n");

    let mut song = String::new();
    for day_nbr in 1..13 {
        song.push_str(&format!(
            "On the {} day of Christmas\n",
            day_string(day_nbr)
        ));

        song.push_str(&get_giver_phrase(day_nbr));

        for gift_nbr in (1..(day_nbr + 1)).rev() {
            song.push_str(&gift(day_nbr, gift_nbr))
        }

        song.push_str("\n");
    }

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

I'm not going to go into detail, but here's an improvement: you take reference to all of your string literals you return.

let x: &'static str = "abc";

Is valid code. That is to say, string literals have the type &str already. str is the data itself. It's unsized since you don't know the length of an arbitrary string (well, technically you do with string literals. That's why b"text" exists), hence it must always live under some indirection.

Similarly, there's no need to take reference to the &str again when calling push_str(). Finally, day_string can also return a &str.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.