Created
March 22, 2025 11:35
-
-
Save xiaozhiliaoo/fa84b3dbfd2cb63d5374b368765d2979 to your computer and use it in GitHub Desktop.
rust demo:cannot borrow `*user` as mutable more than once at a time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::collections::HashMap; | |
| fn main() { | |
| } | |
| #[derive(Debug)] | |
| struct BigUser { | |
| liquidation: i32, | |
| } | |
| #[derive(Debug)] | |
| struct User { | |
| symbols: HashMap<String, String>, | |
| one_symbol: String, | |
| } | |
| fn fun2(user: &mut BigUser) {} | |
| fn fun3(user: &mut BigUser, data: &mut i32) {} | |
| // cannot borrow `*user` as mutable more than once at a time | |
| fn loop_test(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; | |
| // 在 for 循环中,fun2(user) 尝试再次借用 user 的可变引用,而 liq_ctx 已经是一个可变引用, | |
| for i in vec1.iter() { | |
| if liq_ctx == &123 { | |
| continue; | |
| } | |
| fun2(user); // liq_ctx 的作用域还没有结束 | |
| } | |
| } | |
| fn loop_test_2(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; | |
| // 在 for 循环中,fun2(user) 尝试再次借用 user 的可变引用,而 liq_ctx 已经是一个可变引用, | |
| for i in vec1.iter() { | |
| if liq_ctx == &123 { | |
| continue; | |
| } | |
| } | |
| fun2(user); | |
| } | |
| // cannot borrow `*user` as mutable more than once at a time | |
| fn loop_test_3(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; | |
| // 在 for 循环中,fun2(user) 尝试再次借用 user 的可变引用,而 liq_ctx 已经是一个可变引用, | |
| for i in vec1.iter() { | |
| if liq_ctx == &123 { | |
| fun2(user); | |
| continue; | |
| } | |
| } | |
| } | |
| // 不会发生可变借用:if_test 中,liq_ctx 的作用域在 if 语句结束后就结束了,因此 fun2(user) 可以安全地借用 user。 | |
| // if_test 函数不会发生多次可变借用,因为: | |
| // liq_ctx 的可变引用只在 if 条件判断中被使用,不会导致额外的可变借用。 | |
| // 在调用 fun2(user) 时,liq_ctx 的生命周期已经结束,不会与 user 的可变引用冲突。 | |
| fn if_test(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; // liq_ctx 借用 user.liquidation | |
| if liq_ctx == &123 { | |
| // liq_ctx 的作用域在这里结束,liq_ctx 在这里被最后一次使用.一旦这个条件判断完成,liq_ctx 的作用域就结束了。 | |
| fun2(user); // liq_ctx 的借用已经释放,可以安全地借用 user, fun2(user) 的调用是在 liq_ctx 的作用域结束之后发生的。 | |
| } | |
| // println!("{}", liq_ctx) // ------- first borrow later used here | |
| } | |
| // error[E0499]: cannot borrow `*user` as mutable more than once at a time | |
| // 由于 liq_ctx 的生命周期覆盖了整个函数,Rust 编译器会认为你在调用 fun3 时同时持有了两个可变引用 | |
| fn if_test_2(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; | |
| if liq_ctx == &123 { | |
| fun3(user, liq_ctx); | |
| } | |
| } | |
| // error[E0499]: cannot borrow `*user` as mutable more than once at a time | |
| fn if_test_3(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; | |
| if liq_ctx == &123 { | |
| fun2(user); | |
| } | |
| println!("{}", liq_ctx) | |
| } | |
| // error[E0499]: cannot borrow `*user` as mutable more than once at a time | |
| // if_multi_test 会报错是因为 liq_ctx 的作用域覆盖了整个函数,导致多次可变借用冲突。 | |
| fn if_multi_test(user: &mut BigUser) { | |
| let vec1 = vec![1, 2, 3, 4, 123]; | |
| let liq_ctx = &mut user.liquidation; // liq_ctx 借用 user.liquidation | |
| if liq_ctx == &123 { | |
| fun2(user); | |
| } | |
| if liq_ctx == &123 { | |
| fun2(user); | |
| } | |
| if liq_ctx == &123 { | |
| fun2(user); | |
| } | |
| } | |
| // error[E0499]: cannot borrow `*user` as mutable more than once at a time | |
| // 二次可变借用 | |
| fn no_if_test(user: &mut BigUser) { | |
| let liq_ctx = &mut user.liquidation; | |
| fun3(user, liq_ctx); | |
| } | |
| fn handle_cancel_stop_order(user: &mut User, name: &str) { | |
| // 由于symbol是从user中派生的,且symbol仍然在作用域内,Rust认为user仍然被借用,因此不允许再次借用。 | |
| let symbol = match user.symbols.get_mut(name) { | |
| None => { | |
| return; | |
| } | |
| Some(v) => v, | |
| }; | |
| if symbol.is_empty() { | |
| println!("cancelling stop order"); | |
| } | |
| //change_user(user, symbol); | |
| } | |
| fn handle_cancel_stop_order2(user: &mut User, name: &str) { | |
| let symbol = match user.symbols.get_mut(name) { | |
| None => { | |
| return; | |
| } | |
| Some(v) => v, | |
| }; | |
| if symbol.is_empty() { | |
| println!("cancelling stop order"); | |
| return; | |
| } | |
| change_user2(user); | |
| } | |
| fn change_user(user: &mut User, symbol: &mut String) { | |
| user.one_symbol = symbol.clone(); | |
| println!("change_user: {:#?}", user); | |
| } | |
| fn change_user2(user: &mut User) { | |
| println!("change_user: {:#?}", user); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment