Search code examples
rustscope

Rust variable out of scope within function


I'm fairly new to rust so to start I've decided to write an old-school ascii text adventure with some randomly generated elements. However, I also want that random generation to be seed-based such that map generation with a given seed is identical so that it can be shared. However, when adding a user input section that checks whether the user wants to input a seed manually or generate a random one, the variable I'm using to store the seed falls out of scope despite only existing within one function.

I'm not really sure how rust variable scope works especially since this is all within one function, it's possible I missed an execution path in which seed is not declared but not that I could find.

The code is as follows:

use std::io::{stdin, stdout, Write};

fn main() { // Get a seed for a random number generator
    if input("Initiate with a set seed (y/n)? ").to_lowercase().starts_with('y') {
        loop {
            let input: String = input("Enter positive integer seed or \"Cancel\" to generate a seed: "); // Gets user seed
            if input.to_lowercase() == "cancel" {
                let seed: u64 = 824; // Generate random seed here
                break;
            }
            match input.parse::<u64>() {
                Ok(value) => {let seed: u64 = value; break;}, // Saves input seed
                Err(_e) => {println!("Please enter a positive integer or \"Cancel\" to generate a seed."); continue;} // Retries
            }
        }
    }else{
        let seed: u64 = 824; // Generate random seed here
    }
    println!("Running with seed: {}", seed); // seed is out of scope here
}

fn input(message: &str) -> String {
    print!("{}", message); // Prints specified message without newline
    stdout().flush().expect("StdOut flushing error in input()"); // Flush stdout to print immediately
    let mut input_buffer: String = String::new(); // Declare buffer
    stdin().read_line(&mut input_buffer).expect("Input read error in input()"); // Write to buffer
    return input_buffer; // Return input
}

Solution

  • let creates a new variable that lives at most until the next closing brace. You want to create it only once outside the loop, then set it with plain seed = … (no let!):

    use std::io::{stdin, stdout, Write};
    
    fn main() {
        // Get a seed for a random number generator
        let seed;
        if input("Initiate with a set seed (y/n)? ")
            .to_lowercase()
            .starts_with('y')
        {
            loop {
                let input: String =
                    input("Enter positive integer seed or \"Cancel\" to generate a seed: "); // Gets user seed
                if input.to_lowercase() == "cancel" {
                    seed = 824; // Generate random seed here
                    break;
                }
                match input.parse::<u64>() {
                    Ok(value) => {
                        seed = value;
                        break;
                    } // Saves input seed
                    Err(_e) => {
                        println!("Please enter a positive integer or \"Cancel\" to generate a seed.");
                        continue;
                    } // Retries
                }
            }
        } else {
            seed = 824; // Generate random seed here
        }
        println!("Running with seed: {}", seed); // seed is out of scope here
    }
    
    fn input(message: &str) -> String {
        print!("{}", message); // Prints specified message without newline
        stdout().flush().expect("StdOut flushing error in input()"); // Flush stdout to print immediately
        let mut input_buffer: String = String::new(); // Declare buffer
        stdin()
            .read_line(&mut input_buffer)
            .expect("Input read error in input()"); // Write to buffer
        return input_buffer; // Return input
    }