我编写了一个宏,它在 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) 我尝试实现Dump类似于serdes的proc_macro Serialize。
为了这个目的,我有一个箱子foo包含我的“原始”结构(P1和P2在这种情况下),这应该只是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)
我不知道正确的方法是什么,如何在此板条箱中使用依赖项。我当前的是:

这当然是不可能的。
我想念什么?我该怎么做才能打破依赖圈?
/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 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) 我正在使用宏生成代码,其中包含完全限定的类型路径,如下所示:
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)
如何仅针对这一行禁用警告?
我正在尝试仅使用宏在 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。我怎样才能做到这一点?
我有三个不同的函数,我想根据宏参数调用其中一个函数。这个参数应该被预处理,这就是为什么我认为我需要将其写为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?
我正在编写一个宏,以便方便地将类型变量中的嵌套结构enum与编译时模板相匹配。这个想法是利用 Rust 的模式匹配在结构的某些位置强制执行特定值,或将变量绑定到其他有趣的位置。基本思想在我的实现中有效,但对于嵌套模式却失败了。我相信问题在于,一旦宏输入的一部分被解析为$<name>:pat它以后无法解析为$<name>:tt.
为了避免术语模式的使用不明确,我将根据 Rust 文档使用以下表示法:
matchif let$<name>:pat。这是我正在使用的类型的简化版本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) 我试图为我的特征创建一个派生宏,以简化一些内容。
我遇到了一些问题:
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)
这种行为的原因是什么?
我想使用宏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) 假设我想让以下宏起作用:
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