Iterator :: find中的Mutate项

Jas*_*ens 4 libusb rust

我想使用Iterator::findlibusb::Devices对象,它具有像这样的签名:

fn find<P>(&mut self, predicate: P) -> Option<Self::Item> 
    where Self: Sized, P: FnMut(&Self::Item) -> bool
Run Code Online (Sandbox Code Playgroud)

我想找一个具有特定功能的设备vendor_id,这需要Device::device_descriptor在每个设备上调用.但是,该device_descriptor方法需要&mut每个设备一个,而find方法只给出一个&.

这是否意味着它不可能在任何的迭代器的方法(使用可变方法find,filter等等)?

这是我正在努力工作的例子:

let mut device = context
    .devices()
    .unwrap()
    .iter()
    .find(&mut |dev: &libusb::Device| { 
         dev.device_descriptor().unwrap().vendor_id() == vendor_id
     })
    .unwrap();
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

error: cannot borrow immutable borrowed content `*dev` as mutable
Run Code Online (Sandbox Code Playgroud)

mal*_*rbo 5

这是否意味着它不可能在任何的迭代器的方法(使用可变方法find,filter等等)?

在接收类型参数的方法中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
Run Code Online (Sandbox Code Playgroud)

请注意,此规则也适用于auto deref.

的一些方法Iterator接收类型的参数F: Fn*(Self::Item),例如map,filter_map等.这些方法允许在发生变异的项目的功能.


一个有趣的问题是:为什么有些方法需要Fn*(&Self::Item)和其他方法一样Fn*(Self::item)

需要使用该项的方法filter(如果过滤器函数返回将返回该项true)不能Self::Item作为参数传递给函数,因为这样做意味着将项的所有权赋予函数.出于这个原因,像filterpass &Self::Item这样的方法,所以他们以后可以使用该项目.

另一方面,在将它们用作参数之后,方法喜欢mapfilter_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());
    }
}
Run Code Online (Sandbox Code Playgroud)

filter_map过滤出None的值,并产生在包裹值Some秒.