Rust 中的可变引用传递
Posted
技术标签:
【中文标题】Rust 中的可变引用传递【英文标题】:Mutable pass-by-mutable-reference in Rust 【发布时间】:2021-01-30 05:09:30 【问题描述】:我正在完成这个练习(可变的传递可变引用)并且无法理解结果
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42ff75b2464a99337b7738fba3597512
#[derive(Debug)]
struct Person
name: String,
age: u32,
fn birthday_mutable<'a>(mut person: &'a mut Person, replacement: &'a mut Person)
println!("[InFn] Before : Alice :p : :?, Bob :p : :?", &person, person, &replacement, replacement);
person = replacement;
println!("[InFn] After : Alice :p : :?", &person, person);
fn main()
let mut alice = Person
name: String::from("Alice"),
age: 30,
;
let mut bob = Person
name: String::from("Bob"),
age: 20,
;
println!("[Main] Before : Alice :p : :?, Bob :p : :?", &alice, alice, &bob, bob);
birthday_mutable(&mut alice, &mut bob);
println!("[Main] After : Alice :p : :?, Bob :p : :?", &alice, alice, &bob, bob);
在birthday_mutable 函数中,person 位于一个可变变量中。我们做的第一件事是人=替换;。这会改变我们的 person 变量所指向的内容,并且根本不会修改引用所指向的原始值。
尽管改变了人指向的东西,但结果是这样的
[Main] Before : Alice 0x7ffd0c9b77e0 : Person name: "Alice", age: 30 , Bob 0x7ffd0c9b7820 : Person name: "Bob", age: 20
[InFn] Before : Alice 0x7ffd0c9b7568 : Person name: "Alice", age: 30 , Bob 0x7ffd0c9b7570 : Person name: "Bob", age: 20
[InFn] After : Alice 0x7ffd0c9b7568 : Person name: "Bob", age: 20
[Main] After : Alice 0x7ffd0c9b77e0 : Person name: "Alice", age: 30 , Bob 0x7ffd0c9b7820 : Person name: "Bob", age: 20
根据我的理解,结果不应该是这样吗?
[Main] Before : Alice 0x7ffd0c9b77e0 : Person name: "Alice", age: 30 , Bob 0x7ffd0c9b7820 : Person name: "Bob", age: 20
[InFn] Before : Alice 0x7ffd0c9b7568 : Person name: "Alice", age: 30 , Bob 0x7ffd0c9b7570 : Person name: "Bob", age: 20
[InFn] After : Alice 0x7ffd0c9b7568 : Person name: "Bob", age: 20
[Main] After : Alice 0x7ffd0c9b77e0 : Person name: "Bob", age: 20 , Bob 0x7ffd0c9b7820 : Person name: "Bob", age: 20
谁能解释一下原因?
【问题讨论】:
“这会改变我们的 person 变量所指向的内容,并且根本不会修改引用所指向的原始值” - 我很困惑,因为这是你的答案,alice
的内容没有改变,那为什么会在 main 中打印"Bob"
?
【参考方案1】:
当您输入birthday_mutable
时,堆栈状态的简化图如下:
---- main ----
0x820 bob = Person name: "Bob", age: 20
0x7e0 alice = Person name: "Alice", age: 30
---- birthday_mutable ---
0x570 replacement = 0x820
0x568 person = 0x7e0
让我们将以下突变命名为A
和B
:
fn birthday_mutable<'a>(mut person: &'a mut Person, replacement: &'a mut Person)
^^^A ^^^B
突变A
仅更新存储在地址0x568
中的内容,因此仅影响引用birthday_mutable
的person
参数持有——因为参数对其函数是本地的(即地址0x568
在birthday_mutable
的堆栈帧中),这种突变不会影响调用者。这就是你在这里所做的:
person = replacement;
执行上述语句后,地址0x568
的内存包含值0x820
(因此birthday_mutable
的person
参数现在引用bob
)——你可以通过检查@987654339看到这一点@ 而不是&person
,即person
所指事物的地址,而不是person
本身存储的地址。
突变B
仅更新存储在任何地址 (0x7e0
) 本身保存在地址 0x568
的内容——也就是说,它改变了 person
参数 引用的数据 (即alice
在main
的堆栈帧中)。它是通过在变异时取消引用person
参数来实现的:
*person = Person name: "Charlie".to_owned(), age: 10 ;
Rust 比其他一些系统语言更容易忽略取消引用,因为它有 automatically performs deref coercion in function calls 和字段访问;不过,最好记住幕后发生的事情。
【讨论】:
感谢清晰准确的解释以上是关于Rust 中的可变引用传递的主要内容,如果未能解决你的问题,请参考以下文章
python中的值传递和引用传递(可变对象与不可变对象)也就是赋值的原理-python全部是引用传递