How to get value of variable outside of the for loop

Hello,
I'm currently learning Rust and I'm trying to achieve something, where I define a variable directly in the main function as an i32. The value should then get changed inside of the for-loop, which as far as I have understood is another scope. I therefore need to define the variable inside of the for loop somehow to be the same value as it was directly in the main function, while preventing it from being overwritten every time the for-loop runs.
After the for-loop has run trough I want to pass the "result" outside of the for-loop to get printed out.
How do I achieve this?

So very simplified in pseudo code:

let variable: i32 = 0;

for i in 0..10 {
    // get value of variable here somehow
    // let variable: i32 = variable; would get the value 0 but would overwrite it every time
    variable = variable + 10; // Add 10 every time the loop runs (I can't use i as the variable in my case!)
}
println!("Value of variable after the for-loop is: {}", variable);

I know in other languages like for e.g. Go(lang) it is very easy to pass the variable out of the for-loop and access it inside of the for-loop, because it doesn't have the "scope-mechanic". I'm also pretty sure, that this shouldn't be that hard to achieve with Rust, because it's something very basic, but I haven't found a tutorial on how to achieve this. I only found something that explains how I can pass a variable into a scope but not how to pass it outside and also not how to access it inside the for-loop without overwriting it.

Thank you very much in advance!

Your code is correct (the variable should be declared in an outer scope), except you need to use let mut instead of plain let:

let mut variable: i32 = 0;

Alternatively, in Rust sometimes people prefer to use iterators instead of loops and mutable variables, e.g.:

let same_result_as_the_loop: i32 = (0..10).map(|_| 10).sum();
2 Likes

It's inner scope, therefore it can use any variable defined in the outer scope without problem.

1 Like

Thank you! I asked, because I currently try to make a simple interest calculator with the following code (my example was very simplified):

use std::{io};

fn main() {
    println!("How many years do you plan saving money?");
    let mut inp_year = String::new();
    io::stdin()
        .read_line(&mut inp_year)
        .expect("Failed to read input.");

    println!("How much money do you currently have?");
    let mut inp_current_savings = String::new();
    io::stdin()
        .read_line(&mut inp_current_savings)
        .expect("Failed to read input.");

    println!("How much money do you plan to invest every month?");
    let mut inp_investment_rate = String::new();
    io::stdin()
        .read_line(&mut inp_investment_rate)
        .expect("Failed to read input.");

    println!("What do your estimate your yearly interest would be?");
    let mut inp_interest_rate = String::new();
    io::stdin()
        .read_line(&mut inp_interest_rate)
        .expect("Failed to read input");

    println!(" ");

    // Convert Strings to int32
    let mut investment_rate: i32 = inp_interest_rate.trim().parse().unwrap();
    let years: i32 = inp_year.trim().parse().unwrap();
    let current_savings: i32 = inp_current_savings.trim().parse().unwrap();
    let interest_rate: i32 = inp_interest_rate.trim().parse().unwrap();

    // Do some math
    investment_rate = investment_rate * 12;
    let mut final_amount: i32 = 0;
    // Final amount is 0

    for _i in 0..years {
        // Set variables in this scope to be the same as outside of this scope (as it was trough the user input)
        let current_savings: i32 = current_savings;
        let interest_rate: i32 = interest_rate;
        let investment_rate: i32 = investment_rate;
        if final_amount == 0 {
            final_amount = current_savings;
        }
        final_amount = (final_amount + investment_rate) * (1 + interest_rate);
        // Res should now get "borrowed" out of this for-loop so it can be printed out
        // At this place, the variable shows as being unused
    }
    // Res here wasn't defined in this scope, because the for-loop is another scrope. Therefore, the variable isn't declared and it shows as an error
    // I somehow have to hand it out of the for-loop to set it's value here...
    println!(
        "You would have the following amount in your account after {} years: {}",
        years, final_amount
    );
}

Cargo check and Cargo run doesn't give me any errors or warnings. However when I execute and enter the following values:

How many years do you plan saving money?
10
How much money do you currently have?
0
How much money do you plan to invest every month?
5
What do your estimate your yearly interest would be?
5

I get the following error:

thread 'main' panicked at 'attempt to multiply with overflow', src/main.rs:49:24

However due to using a 32bit integer the result should not overflow. I don't understand the issue at the moment.

Off topic, there are languages without scope-mechanics like bash, or opt-in scope-mechanics like python. But the Go is not one of them. Try run this Go code, which is a direct translation of your (commented) Rust code.

package main

import "fmt"

func main() {
    variable := 0

    for i := 0; i < 10; i++ {
        variable := variable + 10
        fmt.Println("Value of variable within the for-loop is:", variable)
    }

    fmt.Println("Value of variable after the for-loop is:", variable)
}
3 Likes

(Excuse the use of Haskell for the calculation, but…) the overflow seems appropriate, following your code’s logic

$ ghci
GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
Prelude> x = 0
Prelude> f x = (x + 5 * 12) * (1 + 5)
Prelude> take 11 $ iterate f x
[0,360,2520,15480,93240,559800,3359160,20155320,120932280,725594040,4353564600]
Prelude> 2^31 - 1
2147483647
Prelude> 4353564600 > 2147483647
True

Possibly, you didn’t actually mean to have a yearly interest rate of 500% though?

Adding dbg!(final_amount); in the loop gives the same numbers by the way:

[src/main.rs:49] final_amount = 0
[src/main.rs:49] final_amount = 360
[src/main.rs:49] final_amount = 2520
[src/main.rs:49] final_amount = 15480
[src/main.rs:49] final_amount = 93240
[src/main.rs:49] final_amount = 559800
[src/main.rs:49] final_amount = 3359160
[src/main.rs:49] final_amount = 20155320
[src/main.rs:49] final_amount = 120932280
[src/main.rs:49] final_amount = 725594040
thread 'main' panicked at 'attempt to multiply with overflow', src/main.rs:50:24
3 Likes

Copying your code to the playground (with the input replaced with fixed values, since the playground doesn't handle input), doesn't seem to give any errors if the values aren't too large. It gives a warning that the import of std::{io} is unused, since I removed the use of stdin(), but there isn't actually anything majorly wrong with your code. The redeclaration of the variables in the loop is redundant, but doesn't change the behaviour of the code.

It seems from the comments and the redeclaration of the variables that your understanding of scopes is that variables have to somehow be manually moved between scopes. That isn't the case. Variables declared in outer scopes are just available in the inner scope, while variables in the inner scope aren't available in the outer scope. In particular, final_amount is declared outside the for loop, so you can use it both inside and after the for loop. Also, talking about it being "borrowed" out of the loop is the wrong terminology, since borrowing refers to something specific in Rust.

You were right. 5 is actually 500% which causes such a high number, that it overflows. Using float (10% = 0.1) works!

use std::io;

fn main() {
    println!("How many years do you plan saving money?");
    let mut inp_year = String::new();
    io::stdin()
        .read_line(&mut inp_year)
        .expect("Failed to read input.");

    println!("How much money do you currently have?");
    let mut inp_current_savings = String::new();
    io::stdin()
        .read_line(&mut inp_current_savings)
        .expect("Failed to read input.");

    println!("How much money do you plan to invest every month?");
    let mut inp_investment_rate = String::new();
    io::stdin()
        .read_line(&mut inp_investment_rate)
        .expect("Failed to read input.");

    println!("What do your estimate your yearly interest would be?");
    println!("Enter in Decimals (1.0 = 100% & 10% = 0.1)");
    let mut inp_interest_rate = String::new();
    io::stdin()
        .read_line(&mut inp_interest_rate)
        .expect("Failed to read input");

    println!(" ");

    // Convert Strings to int32 and float64s
    let mut investment_rate: f64 = inp_interest_rate.trim().parse::<f64>().unwrap();
    let years: i64 = inp_year.trim().parse().unwrap();
    let current_savings: f64 = inp_current_savings.trim().parse::<f64>().unwrap();
    let interest_rate: f64 = inp_interest_rate.trim().parse::<f64>().unwrap();

    // Do some math
    investment_rate = investment_rate * 12.0;
    let mut final_amount: f64 = 0.0;

    for _i in 0..years {
        // Define variables inside scope
        let current_savings: f64 = current_savings;
        let interest_rate: f64 = interest_rate;
        let investment_rate: f64 = investment_rate;
        if final_amount == 0.0 {
            final_amount = current_savings;
        }
        final_amount = (final_amount + investment_rate) * (1.0 + interest_rate);
    }
    println!(
        "You would have the following amount in your account after {} years: {:.2}",
        years, final_amount
    );
}