Очень новичок в ржавчине и пытаюсь понять, как идиоматически работать с этим перечислением: https://docs.rs/netcdf/latest/netcdf/attribute/enum.AttrValue.html
Как мне написать функцию, которая, учитывая перечисление netcdf::attribute::AttrValue и вариант, в котором я ожидаю, возвращает мне примитив, из которого был построен вариант перечисления? Что-то о деконструкции и универсальных функциях, но я не могу найти хорошее решение с нуля. Вот моя лучшая попытка:
use netcdf;
use std::env;
fn main() -> Result<(), netcdf::error::Error> {
let args: Vec<String> = env::args().collect();
let file = netcdf::open(&args[1])?; // data/CCMP_Wind_Analysis_19930103_V03.0_L4.0.nc
let vwnd = &file.variable("vwnd").expect("Could not find variable 'vwnd'");
// help me re-write this hacky block in a nice function that works for any variant:
let mut units: String = String::from("null");
let x = vwnd.attribute("units").unwrap().value().unwrap(); // here's the AttrValue enum
if let netcdf::attribute::AttrValue::Str(v) = x {
units = v;
}
println!("{}",units);
// hack block complete
return Ok(())
}
Это работает — units на самом деле содержит строку типа String — но это кажется очень неидиоматичным. Как мне превратить это в идиоматическую функцию ржавчины?

Обычно для этого используется трейт TryFrom. Если бы автор библиотеки предоставил экземпляры TryFrom для своего типа, то вы могли бы просто написать String::try_from(v) и получить либо Ok(string), либо соответствующую ошибку.
К сожалению, они этого не сделали. Вы всегда можете сделать это самостоятельно с паттерном newtype, но это будет приличная работа, чтобы заставить все эти типы работать.
Спасибо Сильвио - для тех, кто ищет явный ответ, вот как я интерпретировал совет Сильвио:
use netcdf;
use std::env;
use std::convert::TryFrom;
struct Wrapper{
s: String
}
impl std::convert::TryFrom<netcdf::attribute::AttrValue> for Wrapper {
type Error = &'static str;
fn try_from(value: netcdf::attribute::AttrValue) -> Result<Self, Self::Error> {
if let netcdf::attribute::AttrValue::Str(v) = value {
Ok(Wrapper{s: String::from(v)} )
} else {
Err("nope")
}
}
}
fn main() -> Result<(), netcdf::error::Error> {
let args: Vec<String> = env::args().collect();
let file = netcdf::open(&args[1])?; // data/CCMP_Wind_Analysis_19930103_V03.0_L4.0.nc
let vwnd = &file.variable("vwnd").expect("Could not find variable 'vwnd'");
let units = Wrapper::try_from(vwnd.attribute("units").unwrap().value().unwrap()).unwrap().s;
println!("{:#?}", units);
return Ok(())
}
Я немного удивлен, что для извлечения простого атрибута потребуется столько работы, но это совсем другой вопрос.