如何改变 Iterator::find 的闭包中的项目?
How do I mutate the item in Iterator::find's closure?
我想在 libusb::Devices
对象上使用 Iterator::find
,它的签名如下:
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where Self: Sized, P: FnMut(&Self::Item) -> bool
我想查找具有特定 vendor_id
的设备,这需要在每个设备上调用 Device::device_descriptor
。但是device_descriptor
方法需要给每个设备一个&mut
,而find方法只给一个&
。
这是否意味着不可能在 Iterator 的任何方法(find
、filter
等)上使用可变方法?
这是我正在努力工作的示例:
let mut device = context
.devices()
.unwrap()
.iter()
.find(&mut |dev: &libusb::Device| {
dev.device_descriptor().unwrap().vendor_id() == vendor_id
})
.unwrap();
这是我遇到的错误:
error: cannot borrow immutable borrowed content `*dev` as mutable
Does this mean that it's impossible to use mutable methods on any of the Iterator's methods (find
, filter
, etc.)?
在接收F: Fn*(&Self::Item)
类型参数的方法中,是的。不能调用在引用 (&
) 上期望可变引用 (&mut
) 的方法。例如:
let mut x = vec![10];
// (&x)[0] = 20; // not ok
(&mut x)[0] = 20; // ok
//(& (&x))[0] = 20; // not ok
//(& (&mut x))[0] = 20; // not ok
(&mut (&mut x))[0] = 20; // ok
请注意,此规则也适用于自动取消引用。
Iterator
的某些方法接收 F: Fn*(Self::Item)
类型的参数,如 map
、filter_map
等。这些方法允许函数改变项目。
一个有趣的问题是:为什么有些方法期望 Fn*(&Self::Item)
而其他方法期望 Fn*(Self::item)
?
需要使用该项目的方法,如filter
(如果过滤器函数returns true
,将return该项目),不能通过Self::Item
作为函数的参数,因为这样做意味着将项目的所有权赋予函数。出于这个原因,像 filter
这样的方法通过 &Self::Item
,所以他们可以在以后使用该项目。
另一方面,像map
和filter_map
这样的方法在被用作参数后不需要项目(项目毕竟是被映射的),所以他们将项目作为Self::Item
.
一般情况下,在项目需要变异的情况下,可以使用filter_map
代替filter
的使用。对于您的情况,您可以这样做:
extern crate libusb;
fn main() {
let mut context = libusb::Context::new().expect("context creation");
let mut filtered: Vec<_> = context.devices()
.expect("devices list")
.iter()
.filter_map(|mut r| {
if let Ok(d) = r.device_descriptor() {
if d.vendor_id() == 7531 {
return Some(r);
}
}
None
})
.collect();
for d in &mut filtered {
// same as: for d in filtered.iter_mut()
println!("{:?}", d.device_descriptor());
}
}
filter_map
过滤掉 None
值并在 Some
秒内生成包装值。
答案迁移自:
您可以改用 Iterator::find_map
,它的闭包通过 value 接收元素,然后可以很容易地对其进行变异:
games
.iter_mut()
.find_map(|game| {
let play = rng.gen_range(1..=10);
game.play(play).then(|| game)
})
我想在 libusb::Devices
对象上使用 Iterator::find
,它的签名如下:
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where Self: Sized, P: FnMut(&Self::Item) -> bool
我想查找具有特定 vendor_id
的设备,这需要在每个设备上调用 Device::device_descriptor
。但是device_descriptor
方法需要给每个设备一个&mut
,而find方法只给一个&
。
这是否意味着不可能在 Iterator 的任何方法(find
、filter
等)上使用可变方法?
这是我正在努力工作的示例:
let mut device = context
.devices()
.unwrap()
.iter()
.find(&mut |dev: &libusb::Device| {
dev.device_descriptor().unwrap().vendor_id() == vendor_id
})
.unwrap();
这是我遇到的错误:
error: cannot borrow immutable borrowed content `*dev` as mutable
Does this mean that it's impossible to use mutable methods on any of the Iterator's methods (
find
,filter
, etc.)?
在接收F: Fn*(&Self::Item)
类型参数的方法中,是的。不能调用在引用 (&
) 上期望可变引用 (&mut
) 的方法。例如:
let mut x = vec![10];
// (&x)[0] = 20; // not ok
(&mut x)[0] = 20; // ok
//(& (&x))[0] = 20; // not ok
//(& (&mut x))[0] = 20; // not ok
(&mut (&mut x))[0] = 20; // ok
请注意,此规则也适用于自动取消引用。
Iterator
的某些方法接收 F: Fn*(Self::Item)
类型的参数,如 map
、filter_map
等。这些方法允许函数改变项目。
一个有趣的问题是:为什么有些方法期望 Fn*(&Self::Item)
而其他方法期望 Fn*(Self::item)
?
需要使用该项目的方法,如filter
(如果过滤器函数returns true
,将return该项目),不能通过Self::Item
作为函数的参数,因为这样做意味着将项目的所有权赋予函数。出于这个原因,像 filter
这样的方法通过 &Self::Item
,所以他们可以在以后使用该项目。
另一方面,像map
和filter_map
这样的方法在被用作参数后不需要项目(项目毕竟是被映射的),所以他们将项目作为Self::Item
.
一般情况下,在项目需要变异的情况下,可以使用filter_map
代替filter
的使用。对于您的情况,您可以这样做:
extern crate libusb;
fn main() {
let mut context = libusb::Context::new().expect("context creation");
let mut filtered: Vec<_> = context.devices()
.expect("devices list")
.iter()
.filter_map(|mut r| {
if let Ok(d) = r.device_descriptor() {
if d.vendor_id() == 7531 {
return Some(r);
}
}
None
})
.collect();
for d in &mut filtered {
// same as: for d in filtered.iter_mut()
println!("{:?}", d.device_descriptor());
}
}
filter_map
过滤掉 None
值并在 Some
秒内生成包装值。
答案迁移自:
您可以改用 Iterator::find_map
,它的闭包通过 value 接收元素,然后可以很容易地对其进行变异:
games
.iter_mut()
.find_map(|game| {
let play = rng.gen_range(1..=10);
game.play(play).then(|| game)
})