Принять несколько значений атрибута макроса proc

Я хотел иметь возможность извлекать содержимое из такого атрибута:

#[foreign_key(table = "some_table", column = "some_column")]

Вот как я пытаюсь:

impl TryFrom<&&Attribute> for EntityFieldAnnotation {
    type Error = syn::Error;

    fn try_from(attribute: &&Attribute) -> Result<Self, Self::Error> {
        if attribute.path.is_ident("foreign_key") {
            match attribute.parse_args()? {
                syn::Meta::NameValue(nv) => 
                    println!("NAME VALUE: {:?}, {:?}, {:?}", 
                        nv.path.get_ident(), 
                        nv.eq_token.to_token_stream(),
                        nv.lit.to_token_stream(),
                    ),
                _ => println!("Not interesting")
            }
        } else {
            println!("No foreign key")
        }

    // ... More Rust code
}

Все работает нормально, если я просто поставлю туда только один NameValue. Когда я добавляю запятую, все ломается.

Единственная ошибка: error: unexpected token

Как я могу исправить свою логику, чтобы включить возможность иметь более одного NameValue?

Спасибо

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
0
25
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

MetaNameValue представляет только одну пару имя-значение. В вашем случае он ограничен ,, поэтому вам нужно вместо этого проанализировать все эти значения с разделителями как MetaNameValue.

Вместо вызова parse_args вы можете использовать parse_args_with вместе с Пунктуированный::parse_terminated:

use syn::{punctuated::Punctuated, MetaNameValue, Token};

let name_values: Punctuated<MetaNameValue, Token![,]> = attribute.parse_args_with(Punctuated::parse_terminated).unwrap(); // handle error instead of unwrap

Выше name_values имеет тип Пунктуированный, который является итератором. Вы можете перебирать его, чтобы получить различные MetaNameValue в своем атрибуте.


Обновления на основе комментариев:

Получение значения как String из MetaNameValue:

let name_values: Result<Punctuated<MetaNameValue, Token![,]>, _> = attr.parse_args_with(Punctuated::parse_terminated);

match name_values {
    Ok(name_value) => {
        for nv in name_value {
            println!("Meta NV: {:?}", nv.path.get_ident());
            let value = match nv.lit {
                syn::Lit::Str(v) => v.value(),
                _ => panic!("expeced a string value"), // handle this err and don't panic
            };
            println!( "Meta VALUE: {:?}", value )
        }
    },
    Err(_) => todo!(),
};

Работает нормально, но я изо всех сил пытаюсь получить значение в MetaNameValue. Вы можете помочь?

Pyzyryab 10.04.2022 20:21

Ммм, meta_name_value.lit должно дать вам значение. Можно подробнее, с чем вы боретесь?

Mihir Luthra 10.04.2022 20:25

Извините, я изо всех сил пытаюсь получить &str от meta_name_value.lit

Pyzyryab 10.04.2022 20:33

Попробуйте следовать документам на МетаИмяЗначение. Тип lit это Lit. Перейдите к документу Lit, и вы увидите, что это перечисление с вариантом Lit::Str. Сопоставьте этот вариант, и вы получите LitStr. LitStr имеет метод LitStr::value, который даст вам String.

Mihir Luthra 10.04.2022 20:37

Это именно та часть, где я борюсь. Я сопоставляю LitStr(v) и получаю expected tuple struct or tuple variant, found function syn::Lit` не кортежную структуру или кортежный вариант` Я чего-то не понимаю, или, может быть, мне стоит остановиться до завтра (rofl).

Pyzyryab 10.04.2022 20:42

Вот что я пытаюсь сделать: ``` match name_values ​​{ Ok(name_value) => { for nv in name_value { println!("Meta NV: {:?}", nv.path.get_ident()); пусть значение: &str = match nv.lit { syn::LitStr(v) => v.value() }; println!("Мета-ЗНАЧЕНИЕ: {:?}", значение) } }, Err(_) => todo!(), } ```

Pyzyryab 10.04.2022 20:43

Я обновил свой ответ, чтобы исправить фрагмент. Похоже, вы устали и делаете глупые ошибки, поспи спокойно :).

Mihir Luthra 10.04.2022 20:53

Это LitStr вместо Lit::Str. Усталость реальная. Спасибо за добрые слова в ответ :)

Pyzyryab 10.04.2022 21:00

Другие вопросы по теме