英文:
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() -> 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(())
}
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's how I interpreted Silvio'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) -> 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(())
}
I'm a little surprised so much work would be needed to extract a simple attribute, but that's a different question entirely.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论