应用篋:绑定引用的固定对象借用实例
从可变对象(mutable variable)出发,其引用方式,使用两种不同的借用方式:固定引用(immutable reference)和可变引用(mutable reference)。本节将解释把固定和可变引用绑定到固定对象的借用方式。尤其是当固定对象与固定和可变引用交互在一起时,程序代码将会比较更复杂一些。但是通过这一节学习可以加深对借用对象的生命周期概念的理解。
学习内容
- 了解和学习把固定和可变引用绑定到固定对象的借用实例
篇目
绑定固定引用的固定对象
let immut_and_immut_ref = &immut_instance;
let immut_and_immut_ref = &mut_instance;
上面示意图说明了下面程序可变对象mut_instance
及其固定引用的对象immut_ref
(下面简称为“固定引用的固定对象”或者”引用固定对象“)的生命周期。左边图一直可以使用到它们的生命周期结束,这是下面程序的情况。图上带箭头的连接线,是程序代码顺序,而图上无箭头的连接线说明了对象的生命周期范围。
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_ref.rs // #[cfg(feature = "ok")] let mut mut_instance = String::from("Hello"); mut_instance.push_str(", world"); println!("1. use mut_instance = {}", mut_instance); let immut_ref = &mut_instance; println!("1. use immut_ref = {}", immut_ref); // The variable `mut_instance` borrowed here after move println!("2. use mut_instance = {}", mut_instance); println!("2. use immut_ref = {}", immut_ref); #}
另外一种情况,就是右边示意图,当可变对象mut_instance
需要拿回所有权之时,也是引用固定对象immut_ref
生命周期结束之时。要是还想使用已经结束生命周期的对象immut_ref
,编译器就会告诉我们这是不可以的。在之后的其他实例说明过程中,不再说明左边图的情况,主要说明右边示意图的情况。
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_ref.rs // ANCHOR = "string_ref-error_02" // error[E0502]: cannot borrow `mut_instance` as mutable because it is also borrowed as immutable let mut mut_instance = String::from("Hello"); mut_instance.push_str(", world"); println!("1. use mut_instance = {}", mut_instance); let immut_ref = &mut_instance; println!("1. use immut_ref = {}", immut_ref); // The variable `immut_ref` begin to move here mut_instance.push_str("!"); // The variable `immut_ref` moved here println!("2. use immut_ref = {}", immut_ref); //ERROR // The variable `mut_instance` borrowed here after move println!("2. use mut_instance = {}", mut_instance); #}
要是上面程序,在对象mut_instance
需要拿回所有权以后,不再使用对象immut_ref
,程序一切正常。
下面程序说明了这种直接转移可变对象mut_instance
,或者说使用对象copy_mut_instance
,使得可变对象mut_instance
失去其生命周期,取而代之。在对象copy_mut_instance
取而代之以后,这样,就不再可以使用对象mut_instance
。要是再使用它就会如下下面程序一样,出现编译错误。
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_ref.rs // ANCHOR = "string_ref-error_01" // error[E0382]: borrow of moved value: `mut_instance` let mut mut_instance = String::from("hello"); mut_instance.push_str(", world!"); println!("1. use mut_instance = {}", mut_instance); // The variable `mut_instance` begin to move here let copy_mut_instance = mut_instance; // The variable `mut_instance` moved here // ERROR: The variable `mut_instance` borrowed here after move println!("2. use mut_instance = {}", mut_instance); //ERROR #}
绑定可变引用的固定对象
let immut_and_mut_ref = &mut mut_instance;
上面示意图也是说明下面程序可变对象mut_instance
及其可变引用的对象mut_ref
(下面简称为“可变引用的固定对象”或者”引用固定对象“)mut_ref
的生命周期。
对于这种可变对象及其可变引用的固定对象情况,从借用机制上看,与上面可变类型对象的固定引用的固定对象思路是一样的,不同的是可变引用的固定对象可以修改其可变对象的值,并且修改结果直接改变到可变对象的内容。
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_ref.rs // #[cfg(feature = "cp")] let mut mut_instance = String::from("Hello"); mut_instance.push_str(", world"); println!("1. use mut_instance = {}", mut_instance); // The variable `mut_instance` begin to move here let mut_ref = &mut mut_instance; // The variable `mut_instance` moved here println!("1. use mut_ref = {}", mut_ref); mut_ref.push_str("!"); println!("2. use mut_ref = {}", mut_ref); mut_instance.make_ascii_uppercase(); println!("2. use mut_instance = {}", mut_instance); #}
下面程序说明了,当对象mut_instance
拿回所有权以后,不再可以使用引用固定对象mut_ref
了。
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_ref.rs // ANCHOR = "string_ref-error_03" // error[E0499]: cannot borrow `mut_instance` as mutable more than once at a time let mut mut_instance = String::from("Hello"); mut_instance.push_str(", world"); println!("1. use mut_instance = {}", mut_instance); // The variable `mut_instance` begin to move here let mut_ref = &mut mut_instance; // The variable `mut_instance` moved here println!("1. use mut_ref = {}", mut_ref); mut_ref.push_str("!"); println!("2. use mut_ref = {}", mut_ref); // The variable `mut_ref` begin to move here mut_instance.make_ascii_uppercase(); // The variable `mut_ref` moved here println!("3. use mut_ref = {}", mut_ref); // ERROR // The variable `mut_instance` borrowed here after move println!("2. use mut_instance = {}", mut_instance); #}
绑定不同引用的固定对象
上面示意图的左边分支说明下面程序对象mut_instance
、mut_ref
和immut_ref
的生命周期。这里看到,一个可变对象涉及到其固定引用与可变引用的固定对象的使用方法。要是查看三个对象的内存地址,它们是完全相同的。
下面程序是左边示意图的正确借用方法:
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_refs.rs // #[cfg(feature = "ok")] let mut instance = String::new(); instance.push_str("hello"); let mut_ref :&mut String = &mut instance; mut_ref.push_str(" world"); let immut_ref :&String = mut_ref; println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); mut_ref.make_ascii_uppercase(); // immut_ref is moved after here //println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); instance.push('!'); // mut_ref is moved after here //println!("immut_ref = {}", mut_ref); println!("instance = {}", instance); #}
下面程序说明了固定对象immut_ref
的生命周期编译错误问题:
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_refs.rs // ANCHOR = "string_refs-error_01" // error[E0502]: cannot borrow `*mut_ref` as mutable because it is also borrowed as immutable let mut instance = String::new(); instance.push_str("hello"); let mut_ref :&mut String = &mut instance; mut_ref.push_str(" world"); let immut_ref :&String = mut_ref; println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); mut_ref.make_ascii_uppercase(); // immut_ref is moved after here println!("immut_ref = {}", immut_ref); // ERROR println!("mut_ref = {}", mut_ref); instance.push('!'); // mut_ref is moved after here //println!("immut_ref = {}", mut_ref); println!("instance = {}", instance); #}
下面程序说明了固定对象mut_ref
的生命周期编译错误问题:
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_refs.rs // ANCHOR = "string_refs-error_02" // error[E0499]: cannot borrow `instance` as mutable more than once at a time let mut instance = String::new(); instance.push_str("hello"); let mut_ref :&mut String = &mut instance; mut_ref.push_str(" world"); let immut_ref :&String = mut_ref; println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); mut_ref.make_ascii_uppercase(); // immut_ref is moved after here //println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); instance.push('!'); // mut_ref is moved after here println!("mut_ref = {}", mut_ref); // ERROR println!("instance = {}", instance); #}
上面示意图的右边分支是另外一种可能性。上面左边和右边示意图的分支仅仅是下面代码不同。左边分支示意图的对象immut_ref
的值取自于引用对象mut_ref
,而右边分支示意图的对象immut_ref
的值直接取自于instance
的引用:
# #![allow(unused_variables)] #fn main() { // left side image //let immut_ref :&String = mut_ref; // right side image let immut_ref :&String = &instance; #}
对于这种情况,下面程序给出了对象mut_ref
的生命周期编译错误问题:
# #![allow(unused_variables)] #fn main() { // File: ./examples/mut_var_sized/string_refs.rs // ANCHOR = "string_refs-error_03" // error[E0502]: cannot borrow `instance` as immutable because it is also borrowed as mutable let mut instance = String::new(); instance.push_str("hello"); let mut_ref :&mut String = &mut instance; mut_ref.push_str(" world"); //let immut_ref :&String = mut_ref; let immut_ref :&String = &instance; println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); // ERROR mut_ref.make_ascii_uppercase(); // immut_ref is moved after here //println!("immut_ref = {}", immut_ref); println!("mut_ref = {}", mut_ref); instance.push('!'); // mut_ref is moved after here //println!("mut_ref = {}", mut_ref); println!("instance = {}", instance); #}
下面示意图说明还有一些其他更多的可能性。