有没有办法让宏替换字符串中的东西?

Is there a way to make a macro replace things in strings?

该宏应该能够通过参数替换字符串中的条目。例如,这会起作用:

let string = "Hello, world!";
replace_macro!(string, "world", "Rust"); // Hello, Rust!

我不确定该怎么做,因为我之前尝试编写一个常规函数并调用它在宏中不起作用。如果可能的话,我想使用 macro_rules 而不是 proc 宏。

这是不可能的。宏无法检查 and/or 更改变量的值。

如果文字嵌入调用中是可能的 (replace_macro!("Hello, world!", "world", "Rust");) 但需要 proc-macro: macro_rules! 宏无法检查 and/or 更改文字。

使用 proc 宏相当简单:

use quote::ToTokens;
use syn::parse::Parser;
use syn::spanned::Spanned;

type Args = syn::punctuated::Punctuated<syn::LitStr, syn::Token![,]>;

#[proc_macro]
pub fn replace_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input_span = input.span();

    let args = match Args::parse_terminated.parse(input) {
        Ok(args) => Vec::from_iter(args),
        Err(err) => return err.into_compile_error().into(),
    };
    let (original, text, replacement) = match args.as_slice() {
        [original, text, replacement] => (original.value(), text.value(), replacement.value()),
        _ => {
            return syn::Error::new(
                input_span,
                r#"expected `"<original>", "<text>", "<replacement>"`"#,
            )
            .into_compile_error()
            .into()
        }
    };

    original
        .replace(&text, &replacement)
        .into_token_stream()
        .into()
}

它解析由逗号分隔的三个字符串文字的列表,然后调用 str::replace() 来完成真正的工作。