Rust 惯用的组合方式';密钥存在';与';如果是正确的类型';解析toml
我正在分析这个Rust 惯用的组合方式';密钥存在';与';如果是正确的类型';解析toml,rust,toml,Rust,Toml,我正在分析这个 [xxxxx] drive0={} drive1={path="xxxx"} ... 有时有一条路,有时没有 我有工作代码,但我仍在努力学习做事情的惯用方法。代码: for i in 0..8 { let drive_name = format!("drive{}", i); if dmap.contains_key(&drive_name) { if let Some(d) = config[dr
[xxxxx]
drive0={}
drive1={path="xxxx"}
...
有时有一条路,有时没有
我有工作代码,但我仍在努力学习做事情的惯用方法。代码:
for i in 0..8 {
let drive_name = format!("drive{}", i);
if dmap.contains_key(&drive_name) {
if let Some(d) = config[drive_name].as_table() {
this.units.push(Rkunit::new(true));
if d.contains_key("path") {
if let Some(path) = d["path"].as_str() {
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
.unwrap();
this.units[i].file.replace(file);
}
}
} else {
this.units.push(Rkunit::new(false));
}
}
}
我预料到了
if let Some(path) = d["path"].as_str()
(如果d.包含()行,则不带)
将处理这两种情况-即没有“路径”和“路径”不是字符串,但它不是。与相同,也包含\u键(驱动器名称)
我尝试了各种各样的语法猜测,看看是否可以避免另一个嵌套的if,并找到一个
那么,有没有更好的方法,或者这是最好的方法呢。欢迎对解析toml的任何其他评论。这里有一些方法可能是有效的。由于您的代码非常复杂,并且使用非std API,因此很难看出我的更改是否有用:
使用您的通用代码结构,但组合使用.contains
,并将包含的值应用于模式.get(…).map(…)
x.get(y)
返回一个选项值,允许您访问整个选项API,这与x[y]
不同,如果密钥不存在,它会死机
if let Some(d)=config.get(&drive_name).map(|c|c.as_table()){
this.units.push(Rkunit::new(true);
如果让Some(path)=d.get(“path”)。然后(String::as_str){
}
}否则{
this.units.push(Rkunit::new(false));
}
你可以在一些准备工作中使用match语句。我个人更喜欢这样,因为它使match arms非常明确,但我认为它没有那么惯用:
let drive=config.get(&driver_name);//返回一个选项
让path=drive.map(|d |.get(“path”);//返回一个选项
匹配(驱动器、路径){
(一些(d),一些(p))=>{
this.units.push(Rkunit::new(true));
让file=OpenOptions::new()
.读(真)
.写(真)
.create(true)
.open(路径)
.unwrap();
这个.units[i].file.replace(p);
}
(部分(d),无)=>{
this.units.push(Rkunit::new(true);
}
_ => {
this.units.push(Rkunit::new)(false);
}
}
<>我想1。这是更习惯的,但我确实看到了这两个词,这可能更像是一个风格的问题。作曲选项当然是惯用的包含和访问。 < P>有人可能认为选择链接更习惯,但更难追随。
config.get(&driver_name)
.or_else(|| { // no drive, passing None all the way down
this.units.push(Rkunit::new(false));
None
})
.and_then(|drive| { // having a drive, trying to get a path
this.units.push(Rkunit::new(true));
drive.as_table().get("path")
})
.map(|path| { // only having a path, we're doing the thing
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path.as_str()) // as_str is there
.unwrap();
this.units[i].file.replace(file);
});
// also "unused Option" warning, because map returns an Option<()>
config.get(&driver\u name)
.或| |{//没有车,一路都没有经过
this.units.push(Rkunit::new(false));
没有一个
})
.然后(| drive |{//有一个驱动器,试图找到一条路径
this.units.push(Rkunit::new(true));
drive.as_table().get(“路径”)
})
.map(| path |{//只有一条路径,我们正在做这件事
让file=OpenOptions::new()
.读(真)
.写(真)
.create(true)
.open(path.as_str())//as_str在那里
.unwrap();
this.units[i].file.replace(文件);
});
//还有“未使用的选项”警告,因为映射返回一个选项
基于对索曼纽姆回答的轻微推敲,我以这个结尾。它感觉更脆,我学到了一些更地道的语言
for i in 0..8 {
let drive_name = format!("drive{}", i);
if let Some(drive) = dmap.get(&drive_name).and_then(|x| x.as_table()) {
this.units.push(Rkunit::new(true));
if let Some(path) = drive.get("path").and_then(|x| x.as_str()) {
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
.unwrap();
this.units[i].file.replace(file);
}
} else {
this.units.push(Rkunit::new(false));
}
}
我知道任何配置错误都会被默默地忽略。但这正是我想要的。如果给出了非法路径,可能不应该爆炸->稍后->非标准API是什么意思?@pm100非标准API:基本上使用非标准API,所以我无法在rust Playder中测试它,因为我无法访问您正在使用的API。谢谢,v有用。我不知道我可以在元组上进行那种奇特的匹配。但是第一个对我来说似乎最容易遵循。好吧,我尝试合并你的#1,但它无法编译。我不明白为什么不。rust抱怨第三行的d.get是错误的。说d是一个选项,我不知道。因为第一个应该是“未选择”的e config.get.(我修复了第2行中的小错误)@pm100它可能取决于as_table()
返回的内容。在我的示例中,它假设as_table()
返回某种类似于HashMap的API。例如,工作正常。检查as_table()的API返回并在第二个if语句中相应地使用它。@JohnKugelman它不使用和_then
,区别只在于必须返回一些(())
显然,我不会称之为惯用语。函数式调用链不应该真的有副作用。在这种情况下,遵守函数式惯用语会带来更大的代码膨胀