应用篋:循环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); #}
参考资料
- rust-for-loop
- understanding-rust-loops
- fighting-the-borrow-checker-in-a-loop
- rust-by-example/flow_control
- whats-the-difference-between-for-x-in-b-and-for-x-in-b-into-iter
- how-can-i-do-a-mutable-borrow-in-a-for-loop
- pointers-in-rust-a-guide
- rust-ref
- search?q=rust+mutable+borrow+in+loop
- what-is-the-difference-between-iter-and-into-iter
- a-journey-into-iterators
- yarit-yet-another-rust-iterators-tutorial
- effectively-using-iterators-in-rust
# #![allow(unused_variables)] #fn main() { {{ #include ../../../../hello-borrowing/bin-hello/examples/for_loop/mut_string.rs:feature-okey }} #}