Reputation: 1365
I would like to use Iterator::find
on libusb::Devices
object, which has a signature like so:
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where Self: Sized, P: FnMut(&Self::Item) -> bool
I want to find a device with a particular vendor_id
, which requires calling Device::device_descriptor
on each device. However, the device_descriptor
method requires a &mut
to each device, and the find method only gives a &
.
Does this mean that it's impossible to use mutable methods on any of the Iterator's methods (find
, filter
, etc.)?
Here's the example I'm trying to get working:
let mut device = context
.devices()
.unwrap()
.iter()
.find(&mut |dev: &libusb::Device| {
dev.device_descriptor().unwrap().vendor_id() == vendor_id
})
.unwrap();
Here is the error I'm getting:
error: cannot borrow immutable borrowed content `*dev` as mutable
Upvotes: 6
Views: 1061
Reputation: 7579
Answer migrated from: How can I apply mutating method calls to each struct when using Iter::find?
You can use Iterator::find_map
instead, whose closure takes in elements by value which can then be easily mutated:
games
.iter_mut()
.find_map(|game| {
let play = rng.gen_range(1..=10);
game.play(play).then(|| game)
})
Upvotes: 1
Reputation: 11177
Does this mean that it's impossible to use mutable methods on any of the Iterator's methods (
find
,filter
, etc.)?
In the methods that receive a parameter of type F: Fn*(&Self::Item)
, yes. One cannot call a method that expects a mutable reference (&mut
) on a reference (&
). For example:
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
Note that this rule also applies to auto deref.
Some methods of Iterator
receive a parameter of type F: Fn*(Self::Item)
, like map
, filter_map
, etc. These methods allow functions that mutate the item.
One interesting question is: Why do some methods expect Fn*(&Self::Item)
and others Fn*(Self::item)
?
The methods that will need to use the item, like filter
(that will return the item if the filter function returns true
), cannot pass Self::Item
as parameter to the function, because doing that means give the ownership of the item to the function. For this reason, methods like filter
pass &Self::Item
, so they can use the item later.
On the other hand, methods like map
and filter_map
do not need the item after they are used as arguments (the items are being mapped after all), so they pass the item as Self::Item
.
In general, it is possible to use filter_map
to replace the use of filter
in cases that the items need to be mutated. In your case, you can do this:
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());
}
}
The filter_map
filters out None
values and produces the wrapped values in Some
s.
Upvotes: 6