Существует ли какой-либо возможный API, например field_count()
, или это возможно получить только через макросы?
Нет такого встроенного API, который позволял бы вам получать эту информацию во время выполнения. Rust не имеет отражения во время выполнения (см. этот вопрос для получения дополнительной информации). Но это действительно возможно через proc-макросы!
Примечание: proc-макросы отличаются от "макроса в примере" (который объявлен через macro_rules!
). Последний не такой мощный, как proc-макросы.
Если это достижимо с помощью макросов, как это должно быть реализовано?
( Это не введение в proc-макросы; если тема для вас совершенно новая, сначала прочтите введение в другом месте. )
В proc-макросе (например, пользовательском производном) вам как-то нужно получить определение структуры как TokenStream
. Де-факто решение использовать TokenStream
с синтаксисом Rust состоит в том, чтобы проанализировать его с помощью syn
:
#[proc_macro_derive(FieldCount)]
pub fn derive_field_count(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
// ...
}
Тип input
равен ItemStruct
. Как видите, оно имеет поле fields
типа Fields
. В этом поле вы можете вызвать iter()
, чтобы получить итератор для всех полей структуры, для которого, в свою очередь, вы можете вызвать count()
:
let field_count = input.fields.iter().count();
Теперь у вас есть то, что вы хотите.
Может быть, вы хотите добавить этот field_count()
метод к вашему типу. Вы можете сделать это через пользовательский производный (используя quote
ящик здесь):
let name = &input.ident;
let output = quote! {
impl #name {
pub fn field_count() -> usize {
#field_count
}
}
};
// Return output tokenstream
TokenStream::from(output)
Затем в вашем приложении вы можете написать:
#[derive(FieldCount)]
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
MyStruct::field_count(); // returns 3