拆解Rust中的枚举

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

Deconstructing enums in Rust

问题

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

  1. use netcdf;
  2. use std::env;
  3. fn extract_primitive_value(attr_value: &netcdf::attribute::AttrValue) -> Option<String> {
  4. if let netcdf::attribute::AttrValue::Str(v) = attr_value {
  5. Some(v.clone())
  6. } else {
  7. None
  8. }
  9. }
  10. fn main() -> Result<(), netcdf::error::Error> {
  11. let args: Vec<String> = env::args().collect();
  12. let file = netcdf::open(&args[1])?; // data/CCMP_Wind_Analysis_19930103_V03.0_L4.0.nc
  13. let vwnd = &file.variable("vwnd").expect("Could not find variable 'vwnd'");
  14. if let Some(attr) = vwnd.attribute("units") {
  15. if let Some(units) = extract_primitive_value(attr.value()) {
  16. println!("{}", units);
  17. }
  18. }
  19. Ok(())
  20. }

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:

  1. use netcdf;
  2. use std::env;
  3. fn main() -&gt; Result&lt;(), netcdf::error::Error&gt; {
  4. let args: Vec&lt;String&gt; = env::args().collect();
  5. let file = netcdf::open(&amp;args[1])?; // data/CCMP_Wind_Analysis_19930103_V03.0_L4.0.nc
  6. let vwnd = &amp;file.variable(&quot;vwnd&quot;).expect(&quot;Could not find variable &#39;vwnd&#39;&quot;);
  7. // help me re-write this hacky block in a nice function that works for any variant:
  8. let mut units: String = String::from(&quot;null&quot;);
  9. let x = vwnd.attribute(&quot;units&quot;).unwrap().value().unwrap(); // here&#39;s the AttrValue enum
  10. if let netcdf::attribute::AttrValue::Str(v) = x {
  11. units = v;
  12. }
  13. println!(&quot;{}&quot;,units);
  14. // hack block complete
  15. return Ok(())
  16. }

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:

  1. 感谢Silvio - 对于那些寻求明确答案的人,这是我对Silvio的建议的解释
  2. ```rust
  3. use netcdf;
  4. use std::env;
  5. use std::convert::TryFrom;
  6. struct Wrapper {
  7. s: String
  8. }
  9. impl std::convert::TryFrom<netcdf::attribute::AttrValue> for Wrapper {
  10. type Error = &'static str;
  11. fn try_from(value: netcdf::attribute::AttrValue) -> Result<Self, Self::Error> {
  12. if let netcdf::attribute::AttrValue::Str(v) = value {
  13. Ok(Wrapper { s: String::from(v) })
  14. } else {
  15. Err("nope")
  16. }
  17. }
  18. }
  19. fn main() -> Result<(), netcdf::error::Error> {
  20. let args: Vec<String> = env::args().collect();
  21. let file = netcdf::open(&args[1])?; // data/CCMP_Wind_Analysis_19930103_V03.0_L4.0.nc
  22. let vwnd = &file.variable("vwnd").expect("Could not find variable 'vwnd'");
  23. let units = Wrapper::try_from(vwnd.attribute("units").unwrap().value().unwrap()).unwrap().s;
  24. println!("{:#?}", units);
  25. return Ok(())
  26. }

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

  1. 请注意,翻译是根据您提供的代码内容进行的,如果有任何问题,请告诉我。
  2. <details>
  3. <summary>英文:</summary>
  4. 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;

  1. fn try_from(value: netcdf::attribute::AttrValue) -&gt; Result&lt;Self, Self::Error&gt; {
  2. if let netcdf::attribute::AttrValue::Str(v) = value {
  3. Ok(Wrapper{s: String::from(v)} )
  4. } else {
  5. Err(&quot;nope&quot;)
  6. }
  7. }

}

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

}

  1. 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.
  2. </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:

确定