2015-06-17 50 views
9

我正在尝试在Rust中编写一些快速矩阵代码,并且需要确保展开循环。有没有办法创建一个编译时for循环? E.g:我想我可以创建展开循环的宏吗?

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

相关问题