3
votes

Is it possible to write a const function that folds over an iterator? When I try:

const fn foo(s: &str) -> u64 {
    return s.chars().fold(0, |accumulator, char| -> u64 {
        return accumulator ^ (char as u64);
    });
}

I get a compiler error:

error: function pointers in const fn are unstable
 --> src/lib.rs:2:30
  |
2 |       return s.chars().fold(0, |accumulator, char| -> u64 {
  |  ______________________________^
3 | |         return accumulator ^ (char as u64);
4 | |     });
  | |_____^

I presume that my anonymous function |x, y| -> x { ... } is passed as a function pointer to fold() and that's what's causing the error.

Is there some kind of const lambda that I can pass to fold here, or can I just use a for loop instead and accumulate the result in a mutable variable which I then return from the foo function? I have absolutely no Rust experience...

1

1 Answers

5
votes

No, you cannot do this in stable Rust 1.59. You will need to make your function non-const:

fn foo(s: &str) -> u64 {
    s.chars().fold(0, |accumulator, char| {
        accumulator ^ (char as u64)
    })
}

Note I removed the explicit return keywords and closure return type to be idiomatic.

See also:


If you attempt this in nightly Rust:

const fn foo(s: &str) -> u64 {
    s.chars().fold(0, |accumulator, char| {
        accumulator ^ (char as u64)
    })
}

You'll get a different error:

error[E0015]: cannot call non-const fn `core::str::<impl str>::chars` in constant functions
 --> src/lib.rs:2:7
  |
2 |     s.chars().fold(0, |accumulator, char| {
  |       ^^^^^^^
  |
  = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error[E0015]: cannot call non-const fn `<Chars as Iterator>::fold::<u64, [closure@src/lib.rs:2:23: 4:6]>` in constant functions
 --> src/lib.rs:2:15
  |
2 |       s.chars().fold(0, |accumulator, char| {
  |  _______________^
3 | |         accumulator ^ (char as u64)
4 | |     })
  | |______^
  |
  = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

Calling Iterator::fold requires several extensions to the original const fn RFC 911 to be implemented. For example, it's expressly forbidden by the original RFC:

Traits, trait implementations and their methods cannot be const

Since closures are implemented as generics backed by traits, I don't immediately see that they could be easily implemented for the same reason.