gpt4 book ai didi

rust - 使用函数样式(flat_map等)实现递归迭代器的麻烦,该函数样式可处理错误并产生Result <…>类型的项

转载 作者:行者123 更新时间:2023-12-03 11:43:52 25 4
gpt4 key购买 nike

作为一项学习练习,我试图编写一个使用函数样式(使用flat_map之类的函数组合其他迭代器和内容)在文件树上实现迭代器的函数,该函数将生成Result <...>类型的项,并使用表示错误(而不是 panic )。在其他语言(如Python和Kotlin)中,这很容易,但是我听说在Rust中要难一些,我想知道它有多难。我有一个简化的变体工作(对错误感到 panic ),但是我不知道用正确的错误处理方法来编写相同函数的方法。在下面的代码中,我应该在match的分支中产生错误,我已经尝试了所有可能的事情(对我而言),并且我始终会遇到有关match臂中不兼容类型的编译时错误。我在这里想念什么?

use std::path::{Path, PathBuf};
use std::fs;
use std::iter::empty;
use std::iter::once;
use std::error::Error;

type Result<T> = std::result::Result<T, Box<dyn Error>>;

// simpler version which works, but panics on errors
pub fn subdirectories_recursive_panicking(search_root_path: &Path) -> Box<dyn Iterator<Item=PathBuf>> {
if !search_root_path.is_dir() {
return Box::new(empty());
}

let entries = fs::read_dir(search_root_path).unwrap();
Box::new(entries.flat_map(|entry| {
let this_path = entry.unwrap().path();
let nested_paths = subdirectories_recursive_panicking(&this_path);
nested_paths.chain(once(this_path))
}))
}

// below is the unlucky attempt to make it correctly handle errors
// (can't figure out why I get incompatible types in match arms)
// it works, however, if I put `unreachable!()` in place of error expressions, suggesting that the
// other code makes sense, but that would obviously panic on errors
pub fn subdirectories_recursive(search_root_path: &Path) -> Box<dyn Iterator<Item=Result<PathBuf>>> {
if !search_root_path.is_dir() {
return Box::new(empty());
}

let entries_result = fs::read_dir(search_root_path);
match entries_result {
Ok(entries) => {
Box::new(entries.flat_map(|e| {
match e {
Ok(entry) => {
let this_path = entry.path();
let nested_paths = subdirectories_recursive(&this_path);
Box::new(nested_paths.chain(once(Ok(this_path))))
}
Err(e) => {
unreachable!()
// the following doesn't compile:
// Box::new(once(Err(Box::new(e))))
}
}
}))
}
Err(e) => {
unreachable!()
// the following doesn't compile:
// Box::new(once(Err(Box::new(e))))
}
}
}
error[E0308]: `match` arms have incompatible types
--> src/lib.rs:44:25
|
36 | / match e {
37 | | Ok(entry) => {
38 | | let this_path = entry.path();
39 | | let nested_paths = subdirectories_recursive(&this_path);
40 | | Box::new(nested_paths.chain(once(Ok(this_path))))
| | ------------------------------------------------- this is found to be of type `Box<std::iter::Chain<Box<dyn Iterator<Item = std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>>>, std::iter::Once<std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>>>>`
... |
44 | | Box::new(once(Err(Box::new(e))))
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Chain`, found struct `std::iter::Once`
45 | | }
46 | | }
| |_________________- `match` arms have incompatible types
|
= note: expected type `Box<std::iter::Chain<Box<dyn Iterator<Item = std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>>>, std::iter::Once<std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>>>>`
found struct `Box<std::iter::Once<std::result::Result<_, Box<std::io::Error>>>>`

error[E0271]: type mismatch resolving `<std::iter::Once<std::result::Result<_, Box<std::io::Error>>> as Iterator>::Item == std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>`
--> src/lib.rs:51:13
|
51 | Box::new(once(Err(Box::new(e))))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::error::Error`, found struct `std::io::Error`
|
= note: expected enum `std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>`
found type `std::result::Result<_, Box<std::io::Error>>`
= note: required for the cast to the object type `dyn Iterator<Item = std::result::Result<PathBuf, Box<(dyn std::error::Error + 'static)>>>`

最佳答案

在您的外部match中,编译器可以推断出由于返回类型的原因,两个分支都应被强制转换为Box<dyn Iterator>。但是,由于match在内部迭代器类型上是通用的,因此该推断不会扩展到嵌套flat_map中。
要解决此问题,您可以注释匹配的第一个分支,或创建具有预期类型的​​临时变量:

match e {
Ok(_) => Box::new(...) as Box<dyn Iterator<Item = Result<PathBuf>>>,
Err(_) => Box::new(...),
}
// or
let iter: Box<dyn Iterator<Item = Result<PathBuf>>> = match e {
Ok(_) => Box::new(...),
Err(_) => Box::new(...),
}

下一组错误源于这样的事实,即胁迫实际上只在一个层次上发生。 Box<io::Error>可转换为 Box<dyn Error>,但 Result<_, Box<io::Error>>不可转换为 Result<_, Box<dyn Error>>
要解决此问题,您需要主动将其转换为正确的类型:
Box::new(once(Err(Box::new(e) as Box<dyn Error>)))

这是编译版本:
use std::path::{Path, PathBuf};
use std::fs;
use std::iter::empty;
use std::iter::once;
use std::error::Error;

type Result<T> = std::result::Result<T, Box<dyn Error>>;

// simpler version which works, but panics on errors
pub fn subdirectories_recursive_panicking(search_root_path: &Path) -> Box<dyn Iterator<Item=PathBuf>> {
if !search_root_path.is_dir() {
return Box::new(empty());
}

let entries = fs::read_dir(search_root_path).unwrap();
Box::new(entries.flat_map(|entry| {
let this_path = entry.unwrap().path();
let nested_paths = subdirectories_recursive_panicking(&this_path);
nested_paths.chain(once(this_path))
}))
}

// below is the unlucky attempt to make it correctly handle errors
// (can't figure out why I get incompatible types in match arms)
// it works, however, if I put `unreachable!()` in place of error expressions, suggesting that the
// other code makes sense, but that would obviously panic on errors
pub fn subdirectories_recursive(search_root_path: &Path) -> Box<dyn Iterator<Item=Result<PathBuf>>> {
if !search_root_path.is_dir() {
return Box::new(empty());
}

let entries_result = fs::read_dir(search_root_path);
match entries_result {
Ok(entries) => {
Box::new(entries.flat_map(|e| {
let iter: Box<dyn Iterator<Item = Result<PathBuf>>> = match e {
Ok(entry) => {
let this_path = entry.path();
let nested_paths = subdirectories_recursive(&this_path);
Box::new(nested_paths.chain(once(Ok(this_path))))
}
Err(e) => {
// the following doesn't compile:
Box::new(once(Err(Box::new(e) as Box<dyn Error>)))
}
};
iter
}))
}
Err(e) => {
// the following doesn't compile:
Box::new(once(Err(Box::new(e) as Box<dyn Error>)))
}
}
}

关于rust - 使用函数样式(flat_map等)实现递归迭代器的麻烦,该函数样式可处理错误并产生Result <…>类型的项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66297608/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com