Можно ли сгенерировать символ или идентификатор в макросе Rust из строки? Или выполнять строковые операции над идентификатором?
Я хотел сгенерировать метод с учетом символа, но мне нужно уменьшить его до получить имя метода.
get!(B);
// should expand to
fn b() -> B {
// method body
}
Подобраться легко ...
macro_rules! get {
($kind:ident, $method:ident)
=>
{
fn $method() -> $kind {
// method body
}
}
}
get!(B, b)
Но неудовлетворительно.
Я постоянно сталкиваюсь с этим языковым ограничением. Наличие этой функции сделало бы код намного более приятным.
Нет, не существует макроса, который мог бы выполнять такого рода манипуляции со строками для идентификаторов.
Такой макрос можно создать в компиляторе, но, похоже, это не очень популярно; сегодня только экспериментальный concat_idents!
приближается к этому (то есть строковые операции для идентификаторов).
Ваш обходной путь в настоящее время является единственным доступным решением.
Да, я нашел concat_idents!
, но это не то. В любом случае спасибо, приятно осознавать, что это не стоит искать.
Кроме того, у concat_idents!
есть много недостатков, которые, вероятно, также были бы у такого макроса.
Ящик с пастой dtolnay - хороший способ сделать это сейчас: crates.io/crates/paste
Я просто написал для этого процедурный макрос (Кейси).
#![feature(proc_macro_hygiene)]
use casey::lower;
lower!(B); // would render as `b`
proc_macro_hygiene
стабилен начиная с версии 1.45.0, поэтому больше не требует использования по ночам.
Заметка для всех, кто приходит: этот ящик требуется каждую ночь, так что это бесполезно, если вы находитесь в стойле.
Все предыдущие ответы верны; стандартные декларативные макросы не могут этого сделать, и вместо этого вы можете перейти к процедурным макросам. Однако более простой альтернативой процедурным макросам (особенно если, как и я, это та область языка, в которую вы еще не углублялись), является dtolnay's приклеить ящик.
Пример из тех документов:
use paste::paste;
paste! {
// Defines a const called `QRST`.
const [<Q R S T>]: &str = "success!";
}
fn main() {
assert_eq!(
paste! { [<Q R S T>].len() },
8,
);
}
Также поддерживается преобразование регистра, например [<ld_ $reg:lower _expr>]
Релевантно: stackoverflow.com/q/23061702/1233251stackoverflow.com/q/27415011/1233251