Деконструкция перечислений в Rust

Очень новичок в ржавчине и пытаюсь понять, как идиоматически работать с этим перечислением: 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 — но это кажется очень неидиоматичным. Как мне превратить это в идиоматическую функцию ржавчины?

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
0
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Обычно для этого используется трейт 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(())

}

Я немного удивлен, что для извлечения простого атрибута потребуется столько работы, но это совсем другой вопрос.

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