应用篋:循环for语句可变借用实例

学习内容

  • 了解和学习循环for语句可变借用实例

篇目

iter() iterates over the items by reference into_iter() iterates over the items, moving them into the new scope iter_mut() iterates over the items, giving a mutable reference to each item

方法into_iter()与关键词mut的组合结构

  对于具有迭代器Iterator的对象而言,方法into_iter()是完全依赖于其对象类型,且遍历其所有的元素本身。下面通过实例再回顾一下这种方法。

  如下面程序,对象instance的类型是Vec<u8>,这样其元素是原始类型u8,那么方法就遍历其所有原始类型u8的元素。


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_into_iter.rs
    // #[cfg(feature = "okay")]

    let instance = vec![33u8, 42];

    for item in instance.into_iter() {
        //println!("item = {:p}", item);
        println!("item = {:p}", &item);
    }

#}

  其实,上面程序从表面上,方法into_iter(),既看不能让人看到其遍历的元素类型,也看不能让人知道其已经消费了对象instance

  对于第一个问题,为了简单快速了解其元素类型,可以使用上面程序注释掉的宏方法println!(),要是编译没有错误,就说明对象item是引用类型,否则就是非引用类型。

  对于第二个问题,只要在上面程序基础上,在其最后增加一行宏方法println!()代码,如下所示。只要编译该程序,就会出现借用编译错误。说明方法into_iter()已经把对象instance消费掉了。


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_iter_mut.rs
    // #[cfg(feature = "err_09")]

    let instance = vec![33u8, 42];

    for item in instance.into_iter() {
        //item = 1;
        println!("item = {:p}", &item);
    }

    println!("instance = {:?}", instance);

#}

  为了使得对象instance在调用方法into_iter()以后,且修改其元素,而对象instance依然存在,需要借用可变对象instance

  需要指出的是,即使对象instance是可变的,上面程序的方法元素本身也是不可变对象。

  对于方法into_iter(),要是对象类型是&Vec<u8>,其元素是引用类型&u8,那么方法就遍历其所有引用类型&u8的元素。

  下面程序可变对象instance的类型是&mut Vec<u8>,其元素是可变引用类型&mut u8,那么方法就遍历其所有可变引用类型&mut u8的元素。

  下面程序是这里重点解释的结构。三个部分缺一不可:对象instance本身是可变的;其引用本身也是可变的;使用引用作为方法into_iter()的对象。这样可以实现对象instance内容的修改。


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_into_iter.rs
    // #[cfg(feature = "cp")]

    let mut instance = vec![33u8, 42];
    println!("1. instance = {:?}", instance);

    let ref_instance :&mut Vec<u8> = &mut instance;
    println!("1. ref_instance = {:?}", ref_instance);

    for item in ref_instance.into_iter() {
        *item = 1;
    }

    println!("2. ref_instance = {:?}", ref_instance);
    println!("2. instance = {:?}", instance);

#}

  上面程序里,引用对象ref_instance的类型是一种默认情况,即绑定对象ref_instance时,其类型写与不写是一样的意思。但是下面程序的引用对象ref_instance的类型可以不是默认的,而是人为绑定的,这是程序第二段代码的第一行代码。当然程序第二段代码的第二行也是一种默认绑定方式。

  对象instance的类型是&mut [u8],其元素是引用类型&mut u8,那么方法就遍历其所有引用类型&mut u8的元素。这种情况可以把&Vec<u8>&[u8]看作为类似于&String&str


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_into_iter.rs
    // #[cfg(feature = "okey")]

    let mut instance = vec![33u8, 42];
    println!("1. instance = {:?}", instance);
    println!("1. &instance = {:p}", &instance);

    let ref_instance :&mut [u8] = &mut instance;
    //let ref_instance = &mut *instance;
    //let ref_instance :&mut [u8] = &mut *instance;
    println!("1. ref_instance = {:p}", ref_instance);
    for item in ref_instance.into_iter() {        
        *item = 1;
        println!("item = {:p}", item);
    }

    println!("2. ref_instance = {:p}", ref_instance);
    println!("2. instance = {:?}", instance);

#}

方法iter_mut()实例

方法iter_mut() = 方法into_iter()与关键词mut的组合结构

  从上面这行文字可以了解到,接下来说明方法iter_mut()其实就是上面程序代码的简化。

  通过下面程序使用方法iter_mut(),可以了解到它涉及到下面几方面内容:

  • 方法iter_mut()遍历其元素都是引用;
  • 方法iter_mut()遍历其元素都是可变引用;
  • 在调用方法iter_mut()以后,对象instance依然是存在的;
  • 方法iter_mut()隐藏了一个可变借用对象;

# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_iter_mut.rs
    // #[cfg(feature = "ok")]

    let mut instance = vec![33u8, 42];
    println!("1. instance = {:?}", instance);
    println!("1. &instance = {:p}", &instance);

    for item in instance.iter_mut() {
        *item = 1;
        println!("item = {:p}", item);
    }

    println!("2. instance = {:?}", instance);
    println!("2. &instance = {:p}", &instance);

#}

题外话

方法enumerate()实例

  常常希望通过数组的顺序号访问数组。第一个程序说明了这种想法的解决方案:


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_enumerate.rs
    // #[cfg(feature = "cp")]

    let mut instance = vec![33u8; 5];
    
    for index in 0..instance.len() {
        instance[index] = (index as u8) + instance[index];
        println!("{:?}", instance[index]);
    }

    println!("{:?}", instance);

#}

  实现这种想法的比较标准方法是使用标准库方法enumerate()。这个方法不仅遍历了数组的顺序号。而且还遍历其所有元素:


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_enumerate.rs
    // #[cfg(feature = "okey")]

    let mut instance = vec![33u8; 5];
    
    for (index, item) in instance.iter_mut().enumerate() {
        *item = (index as u8) + *item;
        println!("{:?}", *item);
    }

    println!("{:?}", instance);

#}

  第三种是最广泛使用的实现,它摒弃了循环语句:


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_enumerate.rs
    // #[cfg(feature = "okay")]

    let instance: Vec<_> = vec![33u8; 5]
        .into_iter()
        .enumerate()
        .map(|(index, item)| (index as u8) + item)
        .collect();
    
    println!("{:?}", instance);

#}

方法next()实例

  通过下面程序解释使用方法next()的技巧:

可行结构:可变对象+可变迭代器(iter_mut)+方法next


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_next.rs
    // #[cfg(feature = "ok")]

    let mut instance = vec![33u8; 5];
    let mut iter = instance.iter_mut();
    
    loop {
        match iter.next() {
            Some(x) => println!("{:?}", x),
            None => break,
        }
    }
    
    println!("{:?}", instance);

#}

不可行结构:可变对象+迭代器(iter_mut)+方法next


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_next.rs
    // #[cfg(feature = "err_07")]

    let mut instance = vec![33u8; 5];
    //let mut iter = instance.iter_mut();   // OK
    let iter = instance.iter_mut();
    
    loop {
        match iter.next() {
            Some(x) => println!("{:?}", x),
            None => break,
        }
    }
    
    println!("{:?}", instance);
#}

不可行结构:(可变)对象+可变迭代器(into_iter)+方法next


# #![allow(unused_variables)]
#fn main() {
    // File: ./bin-hello/examples/for_loop/for_next.rs
    // #[cfg(feature = "err_08")]

    let instance = vec![33u8; 5];
    //let mut iter = IntoIterator::into_iter(instance);
    let mut iter = instance.into_iter();
    
    loop {
        match iter.next() {
            Some(x) => println!("{:?}", x),
            None => break,
        }
    }
    
    println!("{:?}", instance);
    
#}

参考资料


# #![allow(unused_variables)]
#fn main() {
{{ #include ../../../../hello-borrowing/bin-hello/examples/for_loop/mut_string.rs:feature-okey }}
#}

image