【问题标题】:Mutable pass-by-mutable-reference in RustRust 中的可变引用传递
【发布时间】: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"

标签: rust


【解决方案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 和字段访问;不过,最好记住幕后发生的事情。

【讨论】:

  • 感谢清晰准确的解释
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
相关资源
最近更新 更多