拆解Rust中的枚举

huangapple go评论74阅读模式
英文:

Deconstructing enums in Rust

问题

Here's a more idiomatic Rust function to extract the primitive value from the netcdf::attribute::AttrValue enum variant:

use netcdf;
use std::env;

fn extract_primitive_value(attr_value: &netcdf::attribute::AttrValue) -> Option<String> {
    if let netcdf::attribute::AttrValue::Str(v) = attr_value {
        Some(v.clone())
    } else {
        None
    }
}

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'");

    if let Some(attr) = vwnd.attribute("units") {
        if let Some(units) = extract_primitive_value(attr.value()) {
            println!("{}", units);
        }
    }

    Ok(())
}

I've created the extract_primitive_value function to handle the extraction of the String value from the AttrValue enum variant. This function makes the code more idiomatic and reusable.

英文:

Very new to rust and trying to understand how to idiomatically work with this enum: https://docs.rs/netcdf/latest/netcdf/attribute/enum.AttrValue.html

How do I write a function that, given the netcdf::attribute::AttrValue enum and variant I expect I'm in, returns to me the primitive that the enum variant was constructed from? Something about deconstruction and generic functions, but I can't get a nice solution off the ground. Here's my best attempt:

use netcdf;
use std::env;

fn main() -&gt; Result&lt;(), netcdf::error::Error&gt; {
    let args: Vec&lt;String&gt; = env::args().collect();
    let file = netcdf::open(&amp;args[1])?; // data/CCMP_Wind_Analysis_19930103_V03.0_L4.0.nc
  
    let vwnd = &amp;file.variable(&quot;vwnd&quot;).expect(&quot;Could not find variable &#39;vwnd&#39;&quot;);
  
    // help me re-write this hacky block in a nice function that works for any variant:

    let mut units: String = String::from(&quot;null&quot;);
    let x = vwnd.attribute(&quot;units&quot;).unwrap().value().unwrap(); // here&#39;s the AttrValue enum
    if let netcdf::attribute::AttrValue::Str(v) = x {
        units = v;
    }
    println!(&quot;{}&quot;,units);

    // hack block complete    

    return Ok(())

}

This works - units does in fact have a String-type string in it - but this seems very not idiomatic. How should I turn this into an idiomatic rust function?

答案1

得分: 4

你通常会使用 TryFrom 特性来实现这一点。如果库的作者为他的类型提供了 TryFrom 实例,那么你可以简单地编写 String::try_from(v),然后获得 Ok(string) 或适当的错误。

不幸的是,他们没有这样做。你总是可以使用新类型模式自己完成,但要让所有这些类型正常运行需要相当多的工作。

英文:

You would normally use the TryFrom trait for this. If the library author had provided TryFrom instances for his type, then you could simply write String::try_from(v) and get either an Ok(string) or an appropriate error.

Unfortunately, they didn't do so. You can always do it yourself with the newtype pattern, but it'll be a decent bit of legwork to get all of those types up and running.

答案2

得分: 0

Here's the translated code portion:

感谢Silvio - 对于那些寻求明确答案的人,这是我对Silvio的建议的解释

```rust
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(())
}

我有点惊讶需要这么多工作来提取一个简单的属性,但那是完全不同的问题。


请注意,翻译是根据您提供的代码内容进行的,如果有任何问题,请告诉我。

<details>
<summary>英文:</summary>

Thanks Silvio - for those looking for an explicit answer, here&#39;s how I interpreted Silvio&#39;s advice:

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) -&gt; Result&lt;Self, Self::Error&gt; {

    if let netcdf::attribute::AttrValue::Str(v) = value {
        Ok(Wrapper{s: String::from(v)} )
    } else {
        Err(&quot;nope&quot;)
    }
}

}

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(())

}


I&#39;m a little surprised so much work would be needed to extract a simple attribute, but that&#39;s a different question entirely.

</details>



huangapple
  • 本文由 发表于 2023年5月18日 08:58:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277096.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定