你能用 Rust 写一个照应宏吗?

问题描述 投票:0回答:1

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)。

rust rust-macros
1个回答
0
投票

您可以使用程序宏来做到这一点,因为它们不卫生

宏箱

[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 }
    };
}
© www.soinside.com 2019 - 2024. All rights reserved.