问题描述
我正在解析
[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()
(即没有if d.contains()
行)
将处理两种情况-即没有“ path”和“ path”不是字符串,但是没有。也与contains_key(drive_name)
相同。
我尝试了各种语法猜测,以查看是否可以避免嵌套另一个if并且可以找到一个。
解决方法
这里有一些方法可能是有效的。由于您的代码非常复杂并且使用非标准API,因此很难看出我的更改是否有用:
-
使用常规代码结构,但将
.contains
组合在一起并将所包含的值应用到函数.get(...).map(...)
中。x.get(y)
返回一个Option值,该值使您可以访问整个Option API,而x[y]
与之不同,if let Some(d) = config.get(&drive_name).map(|c| c.as_table()) { this.units.push(Rkunit::new(true); if let Some(path) = d.get("path").and_then(String::as_str) { } } else { this.units.push(Rkunit::new(false)); }
会在密钥不存在时惊慌。let drive = config.get(&driver_name); // return an option let path = drive.map(|d|.get("path")); // returns an option match (drive,path) { (Some(d),Some(p)) => { this.units.push(Rkunit::new(true)); let file = OpenOptions::new() .read(true) .write(true) .create(true) .open(path) .unwrap(); this.units[i].file.replace(p); } (Some(d),None) => { this.units.push(Rkunit::new(true); } _ => { this.units.push(Rkunit::new(false); } }
-
您可以使用match语句进行一些准备工作。我个人比较喜欢这种方式,因为它可以使比赛方式非常明确,但是我认为这种方式不太习惯:
Module not found: Error: Can't resolve './src/js/index.js' in 'C:\Users\Arian\Desktop\Daily Planner 2.0' @ multi babel-polyfill ./src/js/index.js main[1] ERROR in multi (webpack)-dev-server/client?http://localhost:8081 babel-polyfill ./src/js/index.js Module not found: Error: Can't resolve './src/js/index.js' in 'C:\Users\Arian\Desktop\Daily Planner 2.0' @ multi (webpack)-dev-server/client?http://localhost:8081 babel-polyfill ./src/js/index.js main[2]
我认为1.更惯用,但我当然看过两者,而且可能更多是风格问题。当然,撰写选项在包含和访问方面是惯用的。
,有些人可能认为期权的链接更为惯用,但很难遵循。
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<()>
,
基于对massage的答案的轻微按摩,我就此结束了。感觉更脆了,我必须学习更多的惯用锈
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));
}
}
我知道任何配置错误都会被忽略。但这就是我所追求的。如果通过->稍后给出了非法路径,则可能不应该爆炸。