Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I update a variable in a loop to a reference to a value created inside the loop?

I want to enter a loop with a variable n which is borrowed by the function. At each step, n takes a new value; when exiting the loop, the job is done, with the help of other variables, and n will never be used again.

If I don't use references, I have something like this:

fn test(n: Thing) -> usize {
    // stuff
    let mut n = n;
    for i in 1..10 {
        let (q, m) = n.do_something(...);
        n = m;
        // stuff with x
    }
    x
}

x is the result of some computation with q and m but it is an usize type and I didn't encounter any issue in this part of the code. I didn't test this code, but this is the idea. I could make code written like this work.

Since I want to do it with a reference; I tried to write:

fn test(n: &Thing) -> usize {
    // stuff
    let mut n = n;
    for i in 1..10 {
        let (q, m) = (*n).do_something(...);
        n = &m;
        // stuff with x
    }
    x
}

Now the code will not compile because m has a shorter lifetime than n. I tried to make it work by doing some tricky things or by cloning things, but this can't be the right way. In C, the code would work because we don't care about what n is pointing to when exiting the loop since n isn't used after the loop. I perfectly understand that this is where Rust and C differ, but I am pretty sure a clean way of doing it in Rust exists.

Consider my question as very general; I am not asking for some ad-hoc solution for a specific problem.

like image 909
Thomas Baruchel Avatar asked Jan 19 '17 14:01

Thomas Baruchel


People also ask

Can you update a variable inside a while loop?

The best way to make the condition change from True to False is to use a variable as part of the Boolean expression. We can then change the variable inside the while loop.

Can I change the I value inside for loop?

Using While loop: We can't directly increase/decrease the iteration value inside the body of the for loop, we can use while loop for this purpose.

How do you update a value in a for loop in Python?

A for-loop uses an iterator over the range, so you can have the ability to change the loop variable. Consider using a while-loop instead. That way, you can update the line index directly.

Can you modify for loops?

You can modify the loop variable in a for loop, the problem is that for loops in Python are not like "old-style" for loops in e.g. Java, but more like "new-style" for-each loops. In Python, for i in range(0, 10): does not behave like for (int i = 0; i < 10; i++) { , but like for (int i : new int[] {0, 1, ..., 10}} .


1 Answers

As Chris Emerson points out, what you are doing is unsafe and it is probably not appropriate to write code like that in C either. The variable you are taking a reference to goes out of scope at the end of each loop iteration, and thus you would have a dangling pointer at the beginning of the next iteration. This would lead to all of the memory errors that Rust attempts to prevent; Rust has prevented you from doing something bad that you thought was safe.

If you want something that can be either borrowed or owned; that's a Cow:

use std::borrow::Cow;

#[derive(Clone)]
struct Thing;

impl Thing {
    fn do_something(&self) -> (usize, Thing) {
        (1, Thing)
    }
}

fn test(n: &Thing) -> usize {
    let mut n = Cow::Borrowed(n);
    let mut x = 0;

    for _ in 1..10 {
        let (q, m) = n.do_something();
        n = Cow::Owned(m);
        x = x + q;
    }

    x
}

fn main() {
    println!("{}", test(&Thing));
}
like image 178
Shepmaster Avatar answered Sep 30 '22 00:09

Shepmaster