Typecasting and shadowing in Rust

Hi,
I'm a retired programmer (having retired over 10 years ago) and have recently begun to look at Rust - mainly to see what all the hype is all about. So I'm reading the Rust Programming Language book and have just completed section 3.5 (Control Flow) at the end of which are some exercises.

The one I'm looking at is: "Generate the nth Fibonacci Number", which is relatively common as a programming exercise and quite straightforward. However, I thought I'd put the call to my function that does all the work in a loop. In the loop, the user would enter an index into the series and the program would return it before continuing to the next iteration of the loop. I seemed to me to be a job for a while loop. The loop control variable could be set to -1 by user input when the user has finished and wants to exit the loop.

This is where I fall foul of Rust's mutability system and it's type checking. The user entry from stdin is always going to be a String, of course, but I need to pass it to my function as an integer. The only way I can think of to overcome this is to shadow the loop control variable with another let statement, but this then (I think) causes the while loop to loop for ever.

Here's my code:


fn main() {
    // This is just for testing
    //for number in 0..8 {
    //    println!("Fibonacci {number} is: {}", fib(number).to_string());
    //}

    // Print the application name
    println!("Fibonacci calculator");

    // The real code goes here
    // Loop until user inputs -1
    let number: i64 = 0;

    while number >= 0 {
        // Prompt the user for the index required into the Fibonacci series
        println!("Please enter the required Fibonacci index, or -1 to exit");
        let mut requested = String::new();

        io::stdin()
            .read_line(&mut requested)
            .expect("Failed to read line");

        // Check the input is a valid integer
        let number = match requested.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        if number >= 0 {
            println!("You requested index: {number}");
            // Call fib() to calculate the Fibonacci number
            // and print the Fibonacci number out
            println!("Fibonacci({number}) is : {}", fib(number));
        }
    } // end of loop
} // end of main()

fn fib(n: u64) -> u64 {
    if n <= 1 {
        return n;
    } else {
        return fib(n - 2) + fib(n - 1);
    }
}

The output from the program is:

Fibonacci calculator
Please enter the required Fibonacci index, or -1 to exit
8
You requested index: 8
Fibonacci(8) is : 21
Please enter the required Fibonacci index, or -1 to exit
-1
Please enter the required Fibonacci index, or -1 to exit
^C
$ 

Should I perhaps be more patient and wait until I've learnt a bit more about Rust before trying anything like this? Or is there something simple that I've missed?

Many thanks in advance.

You are indeed shadowing, which means the original number never changes, and so your loop never exits.

If you change the initial declaration of number to be let mut, then you can mutate it; then, when you later parse the user input, you can simply do number = match ....

In Rust, variables are immutable by default (as in let number), and must be explicitly declared as mutable (as in let mut number). This is a change from languages like C where mutability is the default, and you must specify immutability.

4 Likes

Ah! brilliant. Thank you. I had to change the parameter to my function to i64 rather than u64, but since the program exits if a negative int is input that should be no problem.

And it all works.

Marked as solved.

Many thanks again. I'd struggled for hours over that.

1 Like

Happy to help! Rust has a lot of things like this, where an unexpected difference to other languages causes confusion. However, I think they make good sense once you understand them. As you read through the Book, it should explain most of these.

I hope you enjoy your Rust journey, and good luck! If you have questions or criticisms, we're always happy to hear them.

3 Likes