Const iteration over const array

Hi all,

I need constant access to each element of a constant array, like this basically:

const FOO: [u8; 4] = [0, 1, 2, 3];

const fn do_something_with_fi<const FI: u8>() -> u8 {
    FI
}

const fn iter() {
    let mut i = 0;
    
    while i < FOO.len() {
        const FI: u8 = FOO[i]; // E0435, because `i` is not `const`
        
        // do something here that requires `FI` to be `const`
        do_something_with_fi::<FI>();
        
        i += 1;
    }
}

Playground.

Is this possible somehow? Maybe behind a feature gate or with some unsafe shenanigans? The error message is quite generic and doesn't give me any clue how to proceed. I found this PR which sounds promising, though without much context.

Could you maybe elaborate on your use-case a bit? Why would you need FI to be const?

You could use recursion like this to get the array elements.

1 Like

Hi @leob,

sure, I've updated the example. I basically need FI to be const, because I use it in a const context.

Hi @H2CO3,

thanks for taking the time. My example was a little bit too unclear, unfortunately. I need FOO[i] to be a constant, because I'm using it in a const context. I get the same error when I use head in your example in a constant context, because head is not const.

Which then opens the question: What does do_something_with_fi do and why wouldn’t const fn do_something_with_fi(fi: u8) -> u8 work? Presumably you use the FI in some type?

No, actually I was only trying to build an minimal example and seemingly failed terribly at that :sweat_smile:. The concrete use-case concerns the constant concatenation of &str with the const_format::concat_cp! macro (which requires its input to be either a literal or a constant, so no variables with let-binding allowed). Here a more concrete example from the rust explorer:

/*
[dependencies]
const_format = "^0.2.30"
*/
use const_format::concatcp;

const FOO: [&str; 4] = ["0", "1", "2", "3"];

const fn concat_each() -> [&'static str; 4] {
    const CONCAT: &str = ".bar";
    
    let mut res = [""; 4];
    let mut i = 0;

    while i < 4 {
        // let VALUE: &str = FOO[i]; 
        // ^ let-binding won't work, because `VALUE` needs to be `const`
        //   if I want to use `concatcp!`

        const VALUE: &str = FOO[i];
        //                      ^ won't compile, because I use the
        //                        non-constant `i` in a constant
        
        res[i] = concatcp!(VALUE, CONCAT);
        //                 ^ is required to be `const`
        
        i += 1;
    }

    res
}

fn main() {
    assert_eq!(concat_each(), ["0.bar", "1.bar", "2.bar", "3.bar"]);
}

FOO is generated by a procedural macro and I want to construct a second constant array BAR like I described in the example, by concatenating a constant &str to each value of FOO.