Rust 宏具有卫生性,所以这不起作用:
macro_rules! λ {
($e:expr) => {
|it| $e
}
}
fn main() {
// this looks like it should emit:
// let f = |it| it > 0
// but it's not quite that
let f = λ!(it > 0);
f(42);
}
这不起作用,因为语法上下文(可能有更好的链接),因此 lambda 预期主体中的
it > 0
实际上不会找到用作 lambda 参数的|it|
。
这通常是您想要的。宏观卫生是一个很棒的功能。
但是,如果我真的想要编写这样的照应宏怎么办? Rust 是否提供了这样做的机制,或者 Rust 中的only解决方案要求宏还单独提供
ident
- 就像λ!(it, it > 0)
中那样?
对于这个特殊情况,这是愚蠢的,因为它比正常的 lambda 长,但这只是一个例子,所以请耐心等待。作为来自不同编程语言的示例,Racket 默认情况下具有卫生功能,但也提供了
syntax-parameter
(其中的 aif
示例确实提供了 this)。
您可以使用程序宏来做到这一点,因为它们不卫生。
[package]
name = "macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.36"
syn = { version = "2.0.65", features = ["full"] }
use proc_macro::TokenStream;
use quote::quote;
use syn::Expr;
#[proc_macro]
pub fn λ(item: TokenStream) -> TokenStream {
let expr = syn::parse_macro_input!(item as Expr);
quote! { |it| #expr }.into()
}
[dependencies]
macros = { path = "./macros" }
use macros::λ;
fn main() {
let f = λ!(it > 0);
dbg!(f(42));
}
[src/main.rs:6:5] f(42) = true
然而,程序宏很难理解,即使是简单的事情也可能很复杂。如果您想继续使用声明性宏(即
macro_rules!
),那么 unhygienic2 板条箱可以为您做到这一点:
macro_rules! λ {
($e:expr) => {
|it| unhygienic2::unhygienic! { $e }
};
}