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

让我们将以下突变命名为AB

fn birthday_mutable<'a>(mut person: &'a mut Person, replacement: &'a mut Person) 
                        ^^^A            ^^^B

突变A 仅更新存储在地址0x568 中的内容,因此仅影响引用birthday_mutableperson 参数持有——因为参数对其函数是本地的(即地址0x568birthday_mutable 的堆栈帧中),这种突变不会影响调用者。这就是你在这里所做的:

person = replacement;

执行上述语句后,地址0x568的内存包含值0x820(因此birthday_mutableperson参数现在引用bob)——你可以通过检查@987654339看到这一点@ 而不是&amp;person,即person所指事物的地址,而不是person本身存储的地址。

突变B 仅更新存储在任何地址 (0x7e0) 本身保存在地址 0x568 的内容——也就是说,它改变了 person 参数 引用的数据 (即alicemain 的堆栈帧中)。它是通过在变异时取消引用person 参数来实现的:

*person = Person  name: "Charlie".to_owned(), age: 10 ;

Rust 比其他一些系统语言更容易忽略取消引用,因为它有 automatically performs deref coercion in function calls 和字段访问;不过,最好记住幕后发生的事情。

【讨论】:

感谢清晰准确的解释

以上是关于Rust 中的可变引用传递的主要内容,如果未能解决你的问题,请参考以下文章

python中的值传递和引用传递(可变对象与不可变对象)也就是赋值的原理-python全部是引用传递

python中的引用传递,可变对象,不可变对象,list注意点

如何在Rust中修改向量的元素?

python中的“引用”和C++的引用

python 引用

Python参数传递(引用传递和值传递)