Есть ли способ подсчета с помощью макросов?

Я хочу создать макрос, который печатает «Hello» определенное количество раз. Он используется как:

many_greetings!(3); // expands to three `println!("Hello");` statements 

Наивный способ создания этого макроса:

 macro_rules! many_greetings { ($times:expr) => {{ println!("Hello"); many_greetings!($times - 1); }}; (0) => (); } 

Однако это не работает, потому что компилятор не оценивает выражения; $times - 1 не вычисляется, а вводится как новое выражение в макрос.

В то время как обычная макросистема не позволяет вам многократно повторять расширение макроса, нет проблем с использованием цикла for в макросе:

 macro_rules! many_greetings { ($times:expr) => {{ for _ in 0..$times { println!("Hello"); } }}; } 

Если вам действительно нужно повторить макрос, вам нужно изучить процедурные macros / компиляторы (которые по состоянию на 1.4 нестабильны и немного сложнее писать).

Редактирование: Вероятно, есть более эффективные способы реализации этого, но я потратил достаточно долго на это на сегодня, так что здесь. repeat! , макрос, который на самом деле дублирует блок кода несколько раз:

main.rs

 #![feature(plugin)] #![plugin(repeat)] fn main() { let mut n = 0; repeat!{ 4 { println!("hello {}", n); n += 1; }}; } 

lib.rs

 #![feature(plugin_registrar, rustc_private)] extern crate syntax; extern crate rustc; use syntax::codemap::Span; use syntax::ast::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult}; use rustc::plugin::Registry; use syntax::util::small_vector::SmallVector; use syntax::ast::Lit_; use std::error::Error; fn expand_repeat(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { let mut parser = cx.new_parser_from_tts(tts); let times = match parser.parse_lit() { Ok(lit) => match lit.node { Lit_::LitInt(n, _) => n, _ => { cx.span_err(lit.span, "Expected literal integer"); return DummyResult::any(sp); } }, Err(e) => { cx.span_err(sp, e.description()); return DummyResult::any(sp); } }; let res = parser.parse_block(); match res { Ok(block) => { let mut stmts = SmallVector::many(block.stmts.clone()); for _ in 1..times { let rep_stmts = SmallVector::many(block.stmts.clone()); stmts.push_all(rep_stmts); } MacEager::stmts(stmts) } Err(e) => { cx.span_err(sp, e.description()); DummyResult::any(sp) } } } #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("repeat", expand_repeat); } 

добавлено в Cargo.toml

 [lib] name = "repeat" plugin = true 

Обратите внимание: если мы действительно не хотим делать цикл, но расширяемся во время компиляции, мы должны делать что-то вроде требующих буквальных чисел. В конце концов, мы не можем оценивать переменные и вызовы функций, которые ссылаются на другие части программы во время компиляции.

Насколько я знаю, нет. Язык макросов основан на сопоставлении шаблонов и подстановке переменных и оценивает только macros.

Теперь вы можете выполнить подсчет с оценкой: это просто скучно … см. Манеж

 macro_rules! many_greetings { (3) => {{ println!("Hello"); many_greetings!(2); }}; (2) => {{ println!("Hello"); many_greetings!(1); }}; (1) => {{ println!("Hello"); many_greetings!(0); }}; (0) => (); } 

Исходя из этого, я вполне уверен, что можно было бы придумать набор макросов для «подсчета» и вызвать различные операции на каждом шаге (со счетом).

  • Компилятор предполагает, что я добавляю «статическое время жизни», потому что тип параметра может не прожить достаточно долго, но я не думаю, что это то, что я хочу
  • Ячейка OpenSSL не скомпилирована в Mac OS X 10.11
  • Когда я не должен реализовывать черту для ссылок на разработчиков этой черты?
  • Когда реализуются блокировки Fn, FnMut и FnOnce?
  • Как мне требовать, чтобы универсальный тип реализовал такую ​​операцию, как Add, Sub, Mul или Div в общей функции?
  • Ошибка генериков: ожидаемый тип параметра, найденная структура
  • Как получить срез в виде массива в Rust?
  • Как я могу создать свою собственную структуру данных с помощью iteratorа, который возвращает изменчивые ссылки?
  • Как написать iterator, который возвращает ссылки на себя?
  • Что такое нелексические времена жизни?
  • Почему добавление жизни к признаку с помощью оператора плюс (Iterator + a) необходимо?
  • Давайте будем гением компьютера.