2015-06-17 3 views
9

Я пытаюсь написать некоторый быстрый матричный код в Rust, и для этого необходимо обеспечить, чтобы циклы были развернуты. Есть ли способ создать цикл компиляции для цикла? Например: Я хочуМогу ли я создать макрос, который разворачивает циклы?

unroll_loop!(f, a, 3); 

генерировать

f(a, 0); 
f(a, 1); 
f(a, 2); 
+2

Я думаю, что вы можете написать расширение синтаксиса для этого, но регулярные макросы macro_rules не помогут вам, потому что у них нет доступных для них переменных или номеров. –

ответ

9

Ну, рода.

macro_rules! unroll { 
    (0, |$i:ident| $s:stmt) => {}; 
    (1, |$i:ident| $s:stmt) => {{ let $i: usize = 0; $s; }}; 
    (2, |$i:ident| $s:stmt) => {{ unroll!(1, |$i| $s); let $i: usize = 1; $s; }}; 
    (3, |$i:ident| $s:stmt) => {{ unroll!(2, |$i| $s); let $i: usize = 2; $s; }}; 
    (4, |$i:ident| $s:stmt) => {{ unroll!(3, |$i| $s); let $i: usize = 3; $s; }}; 
    // ... 
} 

fn main() { 
    unroll!(3, |i| println!("i: {}", i)); 
} 

Вы могли бы возникнуть соблазн спросить «почему вы не просто использовать unroll!($i-1, |$i| $s) для рекурсивного случае?». Это потому, что макросы не могут выполнять математику. Фактически, они не могут сделать любые форму оценки что угодно. Вы в основном ограничены символическими манипуляциями.

Макросы не могут взаимодействовать с типами или значениями в любом случае, что означает следующее не работает, и не может быть сделано для работы:

const N: usize = 3; 
unroll!(N, |i| println!("i: {}", i)); 

Таким образом, вы можете это сделать , но только для литеральных целых чисел, и вам нужно написать явный случай в макросе для каждого целого числа, которое захочет использовать.

+0

Только для тех, кто не знает о плагинах компилятора Rust: одним из возможных решений для этого, которое работает с произвольными (хотя и известными во времени компиляцией) числами, было бы реализовать плагин компилятора, представляющий макрос 'unroll! (...)' с той же семантикой. Однако плагины еще не стабильны. – Regexident

Смежные вопросы