我需要将向量Vec<Result<SomeStruct>>
分成几块,遍历每个片段,做一些工作,如果包含Result<SomeStruct>
则返回错误。
enum SomeStruct {}
#[derive(Debug)]
struct SomeError {}
type Result<T> = std::result::Result<T, SomeError>;
fn foo(v: Vec<Result<SomeStruct>>) -> Result<()> {
for chunk in v.chunks(42) {
for value in chunk {
let value = value?;
//do smth with value
}
}
Ok(())
}
fn main() {
let mut values = Vec::new();
foo(values).unwrap();
}
操场
但是,我收到错误
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> src/main.rs:11:25
|
11 | let value = value?;
| ^^^^^^ the `?` operator cannot be applied to type `&std::result::Result<SomeStruct, SomeError>`
|
= help: the trait `std::ops::Try` is not implemented for `&std::result::Result<SomeStruct, SomeError>`
= note: required by `std::ops::Try::into_result`
似乎?
期望值本身而不是对该值的共享引用,但我无法取消引用共享引用,也不知道如何获取此值本身,因为chunk
这里&[Result<SomeStruct>]
,value
是&Result<SomeStruct>
我该如何解决它?
一般情况
你的函数签名要求你返回一个拥有的SomeError
,但你所拥有的只是对一个的引用。除非你有办法将&SomeError
转换为SomeError
,否则这个问题是无法解决的。
最适用的解决方案是将您的错误更改为可克隆(或可复制,如果适用),然后通过Result::as_ref
和Result::map_err
将您的&Result<T, E>
转换为Result<&T, E>
:
#[derive(Debug, Clone)]
struct SomeError {}
for value in chunk {
let value = value.as_ref().map_err(Clone::clone)?;
// do something with `value`
}
返回对错误的引用也是可能的,但远不常见。这要求错误生存期比调用函数的时间长:
type Result<T, E = SomeError> = std::result::Result<T, E>;
fn foo(v: &[Result<SomeStruct>]) -> Result<(), &SomeError> {
for chunk in v.chunks(42) {
for value in chunk {
let value = value.as_ref()?;
// do something with `value`
}
}
Ok(())
}
fn main() {
let values = Vec::new();
foo(&values).unwrap();
}
另请参阅:
- 如何借用对期权
中内容的引用? - 为什么不鼓励接受对字符串(&String)、Vec(&Vec)或Box(&Box)的引用作为函数参数?
具体案例
由于您拥有Vec
并且没有利用内部迭代器是一个切片的事实,因此您不需要有一个&Result
开始。相反,将Vec
转换为迭代器并take
块长度的片段:
fn foo(v: Vec<Result<SomeStruct>>) -> Result<()> {
let mut v = v.into_iter().peekable();
while v.peek().is_some() {
for value in v.by_ref().take(42) {
let _value = value?;
// do something with `value`
}
}
Ok(())
}
您还可以使用Itertools::chunks
:
use itertools::Itertools; // 0.8.1
fn foo(v: Vec<Result<SomeStruct>>) -> Result<()> {
for chunk in &v.into_iter().chunks(42) {
for value in chunk {
let value = value?;
// do something with `value`
}
}
Ok(())
}
另请参阅:
- 为迭代器实现is_empty的规范方法是什么?
- 是否有等效于切片::块/窗口,供迭代器循环对、三元组等?
- 是否可以使用迭代器将向量分成 10 组?
了解错误
以下是Vec::chunks
的签名:
pub fn chunks(&self, chunk_size: usize) -> Chunks<T>
请注意&self
,因为返回的Chunks<T>
具有Item = &'a [T]
类型的迭代器。 当您迭代此切片(每个块都是一个切片)时,您将获得对T
的引用。 因此,编译器给出的错误:
the trait `std::ops::Try` is not implemented for `&std::result::Result<SomeStruct, SomeError>`
基本上这是说Try
没有为&Result<SomeStruct>
实现。
溶液
我认为不可能拥有切片引用的所有权(不复制)。
复制到Vec
:
您可以在切片(块)上使用to_vec
,前提是SomeStruct
和SomeError
实现Clone
。
使用SomeStruct
作为参考:
由于您的代码返回Ok(())
,因此您可能能够在//do smth with value
中使用&SomeStruct
。 事实上,这是 Rust 中一个常见且非常有用的模式:
fn do_something_with_value(v: &SomeStruct) {
unimplemented!();
}