Вы должны сделать что-то вроде этого непроверенного примера:
use syn::{GenericArgument, PathArguments, Type};
fn extract_type_from_option(ty: &Type) -> Type {
fn path_is_option(path: &Path) -> bool {
leading_colon.is_none()
&& path.segments.len() == 1
&& path.segments.iter().next().unwrap().ident == "Option"
}
match ty {
Type::Path(typepath) if typepath.qself.is_none() && path_is_option(typepath.path) => {
// Get the first segment of the path (there is only one, in fact: "Option"):
let type_params = typepath.path.segments.iter().first().unwrap().arguments;
// It should have only on angle-bracketed param ("<String>"):
let generic_arg = match type_params {
PathArguments::AngleBracketed(params) => params.args.iter().first().unwrap(),
_ => panic!("TODO: error handling"),
};
// This argument must be a type:
match generic_arg {
GenericArgument::Type(ty) => ty,
_ => panic!("TODO: error handling"),
}
}
_ => panic!("TODO: error handling"),
}
}
Не так много вещей, которые можно объяснить, просто "развертывают" различные компоненты типа:
Type
-> TypePath
-> Path
-> PathSegment
-> PathArguments
-> AngleBracketedGenericArguments
-> GenericArgument
-> Type
.
Если есть более простой способ сделать это, я был бы рад узнать это.
Обратите внимание, что, поскольку syn
является синтаксическим анализатором, он работает с токенами. Вы не можете точно знать, что это Option
. Пользователь может, например, набрать std::option::Option
или написать type MaybeString = std::option::Option<String>;
. Вы не можете обрабатывать эти произвольные имена.