Я хотел иметь возможность извлекать содержимое из такого атрибута:
#[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
?
Спасибо
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!(),
};
Ммм, meta_name_value.lit
должно дать вам значение. Можно подробнее, с чем вы боретесь?
Извините, я изо всех сил пытаюсь получить &str
от meta_name_value.lit
Попробуйте следовать документам на МетаИмяЗначение. Тип lit
это Lit
. Перейдите к документу Lit
, и вы увидите, что это перечисление с вариантом Lit::Str
. Сопоставьте этот вариант, и вы получите LitStr
. LitStr
имеет метод LitStr::value
, который даст вам String
.
Это именно та часть, где я борюсь. Я сопоставляю LitStr(v) и получаю expected tuple struct or tuple variant, found function
syn::Lit` не кортежную структуру или кортежный вариант` Я чего-то не понимаю, или, может быть, мне стоит остановиться до завтра (rofl).
Вот что я пытаюсь сделать: ``` 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!(), } ```
Я обновил свой ответ, чтобы исправить фрагмент. Похоже, вы устали и делаете глупые ошибки, поспи спокойно :).
Это LitStr
вместо Lit::Str
. Усталость реальная. Спасибо за добрые слова в ответ :)
Работает нормально, но я изо всех сил пытаюсь получить значение в
MetaNameValue
. Вы можете помочь?