标签: rust-macros

宏生成的代码中未使用的变量

我编写了一个宏,它在 Rust 中实现了类似 Scala 的理解。它将变成这样:

map_for!{
    x <- 0..4;
    y = 2*x;
    z <- 0..1;
    => y+z
}
Run Code Online (Sandbox Code Playgroud)

进入这个:

((0..4).map (move |x| { let y = 2 * x; (x, y) }))
    .flat_map (move |params| {
        let (x, y) = params;
        (0..1).map (move |z| { y + z })
    })
Run Code Online (Sandbox Code Playgroud)

x这是可行的,但编译器会发出“未使用的变量”警告,因为flat_map. 我可以通过在宏中的语句#[allow(unused_variables)]之前添加来禁用警告,但随后它会删除所有未使用的变量警告,因此:let

map_for!{
    x <- 0..4;
    y = 2;
    z <- 0..1;
    => y+z
}
Run Code Online (Sandbox Code Playgroud)

将扩展为:

((0..4).map (move |x| { let y …
Run Code Online (Sandbox Code Playgroud)

rust rust-macros

5
推荐指数
1
解决办法
1054
查看次数

实现proc宏时循环依赖包

我尝试实现Dump类似于serdes的proc_macro Serialize

为了这个目的,我有一个箱子foo包含我的“原始”结构(P1P2在这种情况下),这应该只是dumpable。

接下来,我确实有一个foo_derive包含程序宏本身的板条箱。

因为我想支持多种格式,所以我有第三个板条箱foo_dump,其中包含trait定义Dump(例如,可以转储此结构)和Dumper(这是后端应实现的)。非常直截了当的到这一点。

现在,我想编译它时,出现以下错误:

$ cargo build
error: cyclic package dependency: package `foo v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo)` depends on itself. Cycle:
package `foo v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo)`
    ... which is depended on by `foo_dump v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo_dump)`
    ... which is depended on by `foo_derive v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo_derive)`
Run Code Online (Sandbox Code Playgroud)

我不知道正确的方法是什么,如何在此板条箱中使用依赖项。我当前的是:

依存关系

这当然是不可能的。

我想念什么?我该怎么做才能打破依赖圈?


mcve @ github

/Cargo.toml

[workspace]
members = [ 
    "foo",
    "foo_derive",
    "foo_dump",
]
Run Code Online (Sandbox Code Playgroud)

/foo/Cargo.toml

[package]
name …
Run Code Online (Sandbox Code Playgroud)

rust rust-macros rust-proc-macros

5
推荐指数
1
解决办法
202
查看次数

@符号在声明性宏中的含义是什么?

我已经看到了@宏中使用的符号,但我在Rust Book或任何官方文档或博客文章中都找不到它.例如,在此Stack Overflow答案中,它的使用方式如下:

macro_rules! instructions {
    (enum $ename:ident {
        $($vname:ident ( $($vty: ty),* )),*
    }) => {
        enum $ename {
            $($vname ( $($vty),* )),*
        }

        impl $ename {
            fn len(&self) -> usize {
                match self {
                    $($ename::$vname(..) => instructions!(@count ($($vty),*))),*
                }
            }
        }
    };

    (@count ()) => (0);
    (@count ($a:ty)) => (1);
    (@count ($a:ty, $b:ty)) => (2);
    (@count ($a:ty, $b:ty, $c:ty)) => (3);
}

instructions! {
    enum Instruction {
        None(),
        One(u8),
        Two(u8, u8),
        Three(u8, u8, u8) …
Run Code Online (Sandbox Code Playgroud)

syntax rust rust-macros rust-decl-macros

5
推荐指数
1
解决办法
270
查看次数

如何禁用“不必要的路径消歧器”警告?

我正在使用宏生成代码,其中包含完全限定的类型路径,如下所示:

let vec: Vec::<String>;
Run Code Online (Sandbox Code Playgroud)

注意::之前的额外内容<String>。这是必要的,以便相同的输入标记也可以用于构造函数,通过附加::new()

Vec::<String>::new()
Run Code Online (Sandbox Code Playgroud)

但是,这会产生警告:

let vec: Vec::<String>;
Run Code Online (Sandbox Code Playgroud)

我无法删除 ,::因为然后我收到一个错误:

Vec::<String>::new()
Run Code Online (Sandbox Code Playgroud)

如何仅针对这一行禁用警告?

compiler-warnings rust rust-macros

5
推荐指数
1
解决办法
129
查看次数

如何在 Rust 中对宏进行字符串化之前进行扩展?

我正在尝试仅使用宏在 Rust 中编写一个 quine。为了做到这一点,我将main函数嵌入到 macro 中f1,并尝试嵌入f1in f2with的文字表示stringify!

到目前为止,这是我的代码:

macro_rules!f1{()=>(fn main(){println!("macro_rules!{}\nmacro_rules!f2{{($x:expr)=>(stringify!($x))}}\nf1!();",f2!(f1));})}
macro_rules!f2{($x:expr)=>(stringify!($x))}
f1!();
Run Code Online (Sandbox Code Playgroud)

不出所料,输出是:

macro_rules!f1
macro_rules!f2{($x:expr)=>(stringify!($x))}
f1!();
Run Code Online (Sandbox Code Playgroud)

我需要的是f1在字符串化之前进行扩展以使程序成为quine。我怎样才能做到这一点?

rust rust-macros rust-decl-macros

5
推荐指数
0
解决办法
204
查看次数

Rust 宏:根据表达式调用函数

我有三个不同的函数,我想根据宏参数调用其中一个函数。这个参数应该被预处理,这就是为什么我认为我需要将其写为expr. 但是,我似乎找不到一种方法来区分expr宏中的不同情况。这是我的代码:

fn func_100(){
    println!("Func 100!");
}
fn func_200(){
    println!("Func 200!");
}
fn func_300(){
    println!("Func 300!");
}

macro_rules! generate_func_call {
    (100) => {
        func_100();
    };
    (200) => {
        func_200();
    };
    (300) => {
        func_300();
    }
}

macro_rules! generate_func_call_wrapper {
    ($func: ident, $number: expr) => {
        fn $func(){
            println!("{:?}", $number / 100);
            generate_func_call!($number);
        }
    };
}

generate_func_call_wrapper!(f1,100);
generate_func_call_wrapper!(f2,200);
generate_func_call_wrapper!(f3,300);

fn main(){
    f1();
}
Run Code Online (Sandbox Code Playgroud)

这会生成以下编译时错误:

    generate_func_call!($number);
                        ^^^^^^^ no rules expected this token in macro call
Run Code Online (Sandbox Code Playgroud)

我如何修复这个程序,以便根据表达式调用不同的函数$number

rust rust-macros

5
推荐指数
1
解决办法
3403
查看次数

如何扩展递归宏规则中的子模式?

我正在编写一个宏,以便方便地将类型变量中的嵌套结构enum与编译时模板相匹配。这个想法是利用 Rust 的模式匹配在结构的某些位置强制执行特定值,或将变量绑定到其他有趣的位置。基本思想在我的实现中有效,但对于嵌套模式却失败了。我相信问题在于,一旦宏输入的一部分被解析为$<name>:pat它以后无法解析为$<name>:tt.

为了避免术语模式的使用不明确,我将根据 Rust 文档使用以下表示法:

  • 模式是出现在手臂、语句中的内容,并通过片段说明符在宏中进行匹配matchif let$<name>:pat
  • 匹配是宏中语法规则的左侧。
  • 模板是宏输入的一部分,决定宏如何扩展

游乐场 MCVE

这是我正在使用的类型的简化版本enum

#[derive(Debug, Clone)]
enum TaggedValue {
    Str(&'static str),
    Seq(Vec<TaggedValue>),
}
Run Code Online (Sandbox Code Playgroud)

例如,下面的表达式

use TaggedValue::*;
let expression = Seq(vec![
    Str("define"),
    Seq(vec![Str("mul"), Str("x"), Str("y")]),
    Seq(vec![Str("*"), Str("x"), Str("y")]),
]);
Run Code Online (Sandbox Code Playgroud)

可以通过这个宏调用来匹配:

match_template!(
    &expression,                               // dynamic input structure
    { println!("fn {}: {:?}", name, body) },   // action to take after successful match
    [Str("define"), [Str(name), _, _], …
Run Code Online (Sandbox Code Playgroud)

rust rust-macros

5
推荐指数
1
解决办法
2834
查看次数

为什么必须在proc-macro crate中定义proc-macros?

我试图为我的特征创建一个派生宏,以简化一些内容。

我遇到了一些问题:

the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
Run Code Online (Sandbox Code Playgroud)

并且,在进行小规模修复后proc-macro=true

proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently
functions tagged with `#[proc_macro_derive]` must currently reside in the root of the crate`
Run Code Online (Sandbox Code Playgroud)

这种行为的原因是什么?

language-lawyer rust rust-macros

5
推荐指数
1
解决办法
970
查看次数

我可以重写这个macro_rules吗!宏以与 rustfmt 一起使用的方式吗?

我想使用宏impl为多种具体类型生成相同的块。我的代码目前看起来像这样:

macro_rules! impl_methods {
    ($ty:ty, {  $($method:item);+} ) => {
        impl $ty { $($method)+ }
    };
    ($ty:ty, $($more:ty),+ {$($method:item);+}) => {
        impl_methods!($ty, {$($method);+});
        impl_methods!($($more),+, {$($method);+});
    };
}

struct Hi;
struct Hello;

impl_methods!(Hi, Hello {
    /// `true` if it works, good
    fn works_good(&self) -> bool {
        true
    };

    /// `true` if rustfmt is working
    fn gets_rustfmt(&self) -> bool {
        false
    }
});

assert!(Hi.works_good() && Hello.works_good());
assert!(!(Hi.gets_rustfmt() | Hello.gets_rustfmt()));

Run Code Online (Sandbox Code Playgroud)

这工作得很好(生成了 impl),但它有一个令人沮丧的问题;宏内部定义的方法不会被格式化rustfmt

这是一个小问题,但它很烦人,我很好奇解决方案。我知道 rustfmt 会格式化宏的内容,如果这些内容具有某种形式(是表达式?),因此例如以下宏的内容将被格式化:

macro_rules! fmt_me {
    ($inner:item) …
Run Code Online (Sandbox Code Playgroud)

rust rust-macros

5
推荐指数
1
解决办法
1092
查看次数

有没有办法从传递的 expr 访问 rust 宏中定义的变量?

假设我想让以下宏起作用:

macro_rules! process_numbers {
    ($name:ident, $process:expr) => {
        let $name: Vec<_> = vec![0, 1, 2].iter().map(|num| {
            println!("{}", path); // dummy preprocessing
            let foo = 3; // some other preprocessing involving side-effects
            $process
        }).collect();
    }
}

process_numbers!(name, {
    num + foo
});
Run Code Online (Sandbox Code Playgroud)

有没有办法让我可以从内部num访问?foo$process

rust rust-macros

5
推荐指数
1
解决办法
771
查看次数