Этот макрос должен иметь возможность заменять записи в строке с помощью аргумента. Например, это сработает:
let string = "Hello, world!";
replace_macro!(string, "world", "Rust"); // Hello, Rust!
Я не уверен, как это сделать, так как все мои предыдущие попытки просто написать обычную функцию и вызвать ее внутри макросов не работают. Если возможно, я бы хотел использовать macro_rules вместо макроса proc.
Я видел другой поток StackOverflow, который делает что-то подобное, поэтому мне было интересно, можно ли его адаптировать. stackoverflow.com/questions/55951472/…
@salvage_dev а) Идентификаторы могут быть проверены, а литералы - нет. б) Макрос не создает новый идентификатор, а только заменяет его заранее определенным. Для создания новых идентификаторов также требуется макрос proc.
Это невозможно. Макросы не могут проверять и/или изменять значение переменных.
Это возможно, если литерал встроен в вызов (replace_macro!("Hello, world!", "world", "Rust");
), но требует proc-макроса: macro_rules!
макросы не могут проверять и/или изменять литералы.
Это довольно просто с макросом 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()
для выполнения реальной работы.
Похоже, это сделает именно то, что мне нужно. Однако вы не можете написать proc-макрос и использовать его в том же крейте, и я не очень хочу, чтобы вы просто публиковали работу, которую я не писал. Вы знаете какие-нибудь ящики, которые делают это? Быстрый поиск ничего не дает.
@salvage_dev Не знаю, но я не против, если вы используете этот код :)
Ах, я оставлю ссылку на этот ответ, спасибо за помощь!
Макрос
macro_rules
не может видеть внутреннюю часть строк; он только видит, что ему был передан литерал (даже не строковый литерал). Это определенно потребует макроса proc.