簡體   English   中英

使用 Rust 中的宏創建直到 N 的總和

[英]Create sum of ones till N using macro in Rust

我想創建一個宏來將count!(5)轉換為1+1+1+1+1 最后一個原因是在結構定義中使用count!(N) - 1 ,其中N是一個 const generics。

macro_rules! count {
    (1) => {0};
    (2) => { 1 + count!(1)};
    ($n: tt) => { 1 + count!($n - 1)};
}

struct WindowIterator<I, Item, const N: usize> {
    iter: I,
    values: Box<[Item; count!(N) - 1 ]>,
    index: usize,
}

有了這個定義,我收到一個錯誤,就像no rules expected the token N .

如何更改我的代碼以使其正確?

宏擴展發生在類型推導之前,因此如果您不觸摸N ,它就可以工作。

macro_rules! count {
    ($n: tt) => { $n };
}

struct WindowIterator<I, Item, const N: usize> {
    iter: I,
    values: Box<[Item; count!(N) ]>,
    index: usize,
}

實際上,您甚至不需要宏。

struct WindowIterator<I, Item, const N: usize> {
    iter: I,
    values: Box<[Item; N]>,
    index: usize,
}

Rust 此片段的游樂場鏈接

宏擴展適用於原始令牌。 如果您遵循宏擴展過程...

#![feature(log_syntax)]

macro_rules! count {
    (1) => {{
        log_syntax!(MatchOne count!(1));
        0
    }};
    (2) => {{
        log_syntax!(MatchTwo count!(2));
        0
    }};
    ($n:tt) => {{
        log_syntax!(MatchNumber count!($n));
        1 + count!($n - 1)
    }};
    ($($n:tt)*) => {{
        log_syntax!(MatchAny count!($($n)*));
    }};
}

游樂場

輸出:

MatchNumber count! (5)
MatchAny count! (5 - 1)

第二次調用沒有得到4 ,而是5 - 1 ,原始標記。

你想要的可以用過程宏來完成,例如:

extern crate proc_macro;

use itertools::Itertools; // When std's intersperse() will be stable, can get rid of this.
use proc_macro::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree};

#[proc_macro]
pub fn count(number: TokenStream) -> TokenStream {
    let number = number.to_string().parse().expect("expected a number"); // A simple way to parse int literal without `syn`
    let result = if number == 0 {
        TokenTree::Literal(Literal::u64_unsuffixed(0))
    } else {
        TokenTree::Group(Group::new(
            Delimiter::None,
            std::iter::repeat(TokenTree::Literal(Literal::u64_unsuffixed(1)))
                .take(number)
                .intersperse(TokenTree::Punct(Punct::new('+', Spacing::Alone)))
                .collect(),
        ))
    };
    result.into()
}

但是,這可能不是您想要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM