Using fold with multiple state variables

Hello everyone !

Given the signature of the fold method:

fn fold<B, F>(self, init: B, f: F) -> B
where
    F: FnMut(B, Self::Item) -> B

I was under the impression that the following code should work:

fn main() {
    let n: usize = 10;
    let fib: usize = (0..n).fold(
        (0, 1), |(a, b), _i| {
            let next = a + b;
            a = b;
            b = next;
            (a, b)
        }
    );
    println!("{}", fib.1);
}

Could you help me figure out what I am doing wrong ?

The main problem here is the type annotation fib: usize. It's incorrect since you're defining a tuple. You can either remove it entirely, or specify the tuple type (the latter would give you the choice to use something different from the default i32, though that could also be achieved by using literals with types, such as (0_u64, 1_u64).

Once that is fixed... you can also simplify the a = b; b = next; (a, b) game to just using (b, next) as a return value from the closure; and otherwise you'd need to mark a and b as mutable.

2 Likes

Oops :sweat_smile:, it does make sense since

F: FnMut(B, Self::Item) -> B

Thank you, @steffahn, for the help !

And just in case anyone is interested in a working example:

fn main() {
    let n: usize = 20;
    let fib = (0..n).fold(
        (0, 1), |(mut a, mut b), _i| {
            let next = a + b;
            a = b;
            b = next;
            (a, b)
        }
    );
    println!("{}", fib.1);
}

or an alternative that keeps fib as a scalar value:

fn main() {
    let n: usize = 20;
    let fib: usize = (0..n).fold(
        (0, 1), |(mut a, mut b), _i| {
            let next = a + b;
            a = b;
            b = next;
            (a, b)
        }
    ).1;
    println!("{}", fib);
}

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.