LINUX.ORG.RU

Вложенные циклы макросом на Rust

 ,


0

4

Попытался написать макрос который бы генерировал N вложенных циклов, перебирающих до M и понял, что или я чего-то не понимаю, или на расте это не реализовать. Хочется чего-то типа:

nested_loops![3,10,f()]
,которое бы раскрывлось в
for x1 in 0..10 {
   for x1 in 0..10 {
       for x1 in 0..10 {
         f();
       }
   }
}
, но я уперся в то, что или не понимаю как организовать циклы/рекурсию внутри макросов раста, или в то, что это сделать нельзя. Прочитал маленькую книжку про макрос раста, но ясности не прибавилось.

Сомневаюсь что так можно. Разве что как nested_loops![10,10,10;f()].

Ну а если очень хочется - есть proc-macros. Там всё можно.

RazrFalcon ★★★★★
()
Последнее исправление: RazrFalcon (всего исправлений: 1)

А попробуй сопоставлением по образцу «3». Тогда циклы придется сформировать заранее в самом макросе, но вряд ли тебе понадобится вложенность больше 20

dave ★★★★★
()
Ответ на: комментарий от Crocodoom

Тут не в циклах дело а в понимании границ возможностей макросов.

kremator666
() автор топика
Ответ на: комментарий от red75prim

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

kremator666
() автор топика

Это можно реализовать с помощью TT muncher:

macro_rules! nested_loops {
    ([$end:expr, $($tail:tt)*], $body:stmt) => {
        for _ in 0..$end {
            nested_loops!([$($tail)*], $body);
        }
    };
    ([$end:expr], $body:stmt) => {
        for _ in 0..$end {
            $body;
        }
    };
}

fn main() {
    let mut iteration = 0;
    nested_loops!(
        [10, 10, 10], {
            iteration += 1;
            println!("iteration: {}", iteration);
        }
    );
}

https://play.rust-lang.org/?gist=b9a5dec31636f96b6a5b238ba482d66b&version...

freecoder
()
Ответ на: комментарий от kremator666

Да. При раскрытии макроса перебираются все варианты параметров, первый подходящий раскрывается.

red75prim ★★★
()
Ответ на: комментарий от red75prim

Опередил меня :)

Мой компактный вариант, по мотивам твоей реализации:

macro_rules! nested_loops {
    ($end:expr, $($tail:tt)+) => {
        for _ in 0..$end {
            nested_loops!($($tail)+);
        }
    };
    ($body:stmt) => {
        $body
    };
}

fn main() {
    let mut iteration = 0;
    nested_loops!(10, 10, 10, {
        iteration += 1;
        println!("iteration: {}", iteration);
    });
}

https://play.rust-lang.org/?gist=d5c848ce6c1234fa4507d830667a9f77&version...

freecoder
()

Странные ты книжки читаешь, в Растбуке (хорошее слово, Растбука), в первой редакции, в главе про макросы показан пример рекурсивного макроса. Простым его не назовешь, но технику он иллюстрирует.

Virtuos86 ★★★★★
()
Ответ на: комментарий от freecoder

Я бы iteration сделал беззнаковым целым. В примере оно используется именно в таком контексте, хотя, конечно, это лишь пример.

Virtuos86 ★★★★★
()
macro_rules! nested_loop {
    ($body:stmt) => ($body);
    ($pat:pat = $it:expr, $($tt:tt)*) => {
        for $pat in $it {
            nested_loop!($($tt)*);
        }
    };
}

fn main() {
    nested_loop!(i = 0..5, j = 0..10, {
        println!("i: {}, j: {}", i, j);
    });
}
anonymous
()

Кстати, это не имеет особого отношения к делу, но всё же:

#[macro_use]
extern crate itertools;

fn main() {
    for (i, j, k) in iproduct!(0..4, 0..4, 0..4) {
        println!("i:{}\tj:{}\tk:{}", i, j, k);    
    }
}

Deleted
()
Ответ на: комментарий от freecoder

Выходит, что если мы хотим задавать число циклов не руками через [10,10,10], то нам нужен еще макрос превращающий цифру N в [10, ...Nраз.. 10].

kremator666
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.