【问题标题】:A bit problem about Rust's function parameter and ownership [duplicate]关于 Rust 的函数参数和所有权的一点问题 [重复]
【发布时间】:2021-08-28 10:31:48
【问题描述】:

这是我的问题:

fn main() {
    let mut s = String::from("hello");
    let s1 = &mut s;
    let s2 = s1;

    *s2 = String::from("world1");
    *s1 = String::from("world2");

    println!("{:?}", s);
}

这将导致编译错误,因为 s1 的类型 &mut String 没有实现 Copy 特征。

但是如果我将代码更改如下:

fn c(s: &mut String) -> &mut String {
    s
}

fn main() {
    let mut s = String::from("hello");
    let s1 = &mut s;
    let s2 = c(s1);

    *s2 = String::from("world1");
    *s1 = String::from("world2");

    println!("{:?}", s);
}

它将编译没有任何错误消息。

我知道当一个引用传递给一个函数时,它意味着引用 borrows 是值而不是拥有它。

但在上述情况下,似乎当 s1 被传递给 fn c 并立即返回时, s2 borrowed s1 所以无法取消引用 s1直到 s2 超出它的生命周期。

那么当 s1 被传入 fn c 时发生了什么?

【问题讨论】:

  • 您可以使用let s2 = &mut *s1; 而不是let s2 =c(s1);:引用不是Copy,但您可以像在函数中那样获取新的引用。请注意,这不是答案:我对导致c 中的取消引用的规则不够清楚。
  • 看起来你有两个对同一个字符串的可变引用,但是如果你在*s1 = String::from("world2");之后添加println!("{:?}", s2);,你会得到cannot assign to *s1 because it is borrowed。所以我这是由 NLL 引起的。不过这个问题很有趣。
  • PS:如果你在没有fn c 的情况下重新借用 s1 也会发生同样的情况:let s2 = &mut *s1; 所以我想,在fn c() 的情况下,rustc 正在执行一个隐蔽的重新借用,而在s2 = s1如果它只是在做一个move。相关问题:stackoverflow.com/questions/43036156/…
  • 这绝对是许多 Rust 新手的绊脚石。幸运的是,我认为 Sven 对副本的回答很好地解释了为什么会出现这种情况。
  • 从那个答案来看,使函数编译的另一种方法是明确地给s2 一个引用类型:let s2: &mut _ = s1; 可以正常工作,因为编译器会在已知目的地的任何时候推断重新借用成为可变引用。

标签: rust ownership


【解决方案1】:

根据@Denys Séguret 的提示,我猜当 s1 被传递给 fn C 时,Rust 核心将参数 s1 编译为类似 @987654323 @,所以有一个 s1 的不可变借用。

这就是为什么如果我们把

*s2 = String::from("world1");

后面

*s1 = String::from("world2");

Rust 会告诉我们:

assignment to borrowed `*s1`

当 s2 超出它的生命周期范围时,不再有借用 s1,因此可以再次取消引用 s1。

但我不太确定这是否是正确的解释。

【讨论】:

  • 这似乎是一种特殊情况,因为如果您使用身份函数而不是c,那么它就不起作用了。
  • 恒等函数是什么意思?
  • 没关系......
猜你喜欢
  • 2020-02-16
  • 1970-01-01
  • 2021-12-21
  • 2020-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
相关资源
最近更新 更多