Search code examples
arraysrustconstants

Is there something like C99 designated range initializer for arrays?


The similar question is asked in Is there a way to get C99 array designators or alternative in Rust?, but the answers there cannot initialize a value for a give range.

For example,

int a[10] = { [4 ... 8] = 10 };

How do const arrays in Rust use an initializer on the range? If we don't use const, it can be done by fill() method:

let mut a: [i32; 10] = [0; 10];
a[4..9].fill(10);

But fill() cannot be used in const block.


Solution

  • There is no built-in way to do this, but it's possible to create it yourself with a macro:

    macro_rules! array_ranged_init {
        (
            $default_value:expr
            $(,
                [
                    $($min:literal)?
                    $( .. $($max:literal)? )?
                ] = $value:expr
            )*;
            $len:expr
        ) => {
            {
                let mut array = [$default_value; $len];
                $(
                    #[allow(unused_variables)]
                    let min = 0;
                    $(let min = $min;)?
                    
                    #[allow(unused_variables)]
                    let max = min + 1;
                    $(
                        #[allow(unused_variables)]
                        let max = $len;
                        $(let max = $max;)?
                    )?
                    
                    let mut i = min;
                    while i < max {
                        array[i] = $value;
                        i += 1;
                    }
                )*
                array
            }
        }
    }
    
    

    You can then use the macro like this:

    static DATA: [i32; 10] = array_ranged_init![0, [4..9] = 10; 10];
    
    #[test]
    fn test() {
        assert_eq!(DATA, [0, 0, 0, 0, 10, 10, 10, 10, 10, 0])
    }
    

    This macro allows you to include multiple ranges:

    static DATA: [i32; 12] = array_ranged_init![
        0,
        [1..6] = 4,
        [10..] = 6,
        [..1] = 1,
        [3] = 9;
        12
    ];
    
    #[test]
    fn test() {
        assert_eq!(DATA, [1, 4, 4, 9, 4, 4, 0, 0, 0, 0, 6, 6])
    }