< 返回版块

acodercat 发表于 2020-01-21 16:15

Tags:所有权

fn test1(mut u: &User) {
    u = & User {
        age: 1
    };
}

fn test2(mut u: &User) {
    let t = User {
        age: 1
    };
    u = & t;
}

上面代码中test1不会报错,test2会报下面的错

36 | fn test2(mut u: &User) {
   |                 - let's call the lifetime of this reference `'1`
...
40 |     u = & t;
   |     ----^^^
   |     |   |
   |     |   borrowed value does not live long enough
   |     assignment requires that `t` is borrowed for `'1`
41 | }
   | - `t` dropped here while still borrowed

不理解为什么test1不报错

评论区

写评论
EganLi 2020-02-05 10:12

可以写个代码测试下,给u个数据,打印下函数调用前和调用后的值,就会发现编译器做了很多工作。 对以下内容的回复:

kaoet 2020-01-26 13:13

我认为可以这样理解,test2中由于显式定义了t,致使后续可以让t失效,就像这样:

fn test2<'a>(mut u: &'a User) {
    let t = User {
        age: 1
    };
    u = & t;
    drop(t);
    // u is dangling here!
}

而这在test1中无法做到。 注意到这里u的类型一直是&'a User,而'a中是没有t生存期信息的。因此drop(t)时编译器并不会发现t此时在作用域内有一个合法的引用u,不会阻止drop。

wllenyj 2020-01-25 23:25

同样费解, test1内的user到底是栈上分配的?还是堆上分配的?如果是栈上分配的,那u就应该是悬垂指针,如果是堆上分配那可以不用Box分配堆上数据?难道rust也有栈逃逸操作?

IT写轮眼 2020-01-22 18:03

test1() 不报错, 是因为 u 是诞生在 test1() 世界之外的人, u 进入到 test1() 这个世界, 从这个世界获取了一个物品 User, 然后 u 就带着这件物品 User 离开了 test1(). 物品是否销毁, 关键看他在谁手里. 物品的主人被销毁了, 物品跟随主人一起陪葬

IT写轮眼 2020-01-22 17:54

test2() 中, t 诞生了, 并且他持有了一个物品 User. 但是 t 只能活在 test2() 中, 所以 test2() 结束后, t 也就不存在了, t 持有的物品 User 就跟着t一起陪葬. 但是, t 试图把他持有的物品 User 借给外面的人 u 最后, 物品 User 已经随着 t 陪葬了, 不存在了. u 只拿到一张空头支票

为了避免这种开空头支票的行为, 编译器就帮助检查出这种不法行为, 予以报错

SaylorZhu 2020-01-22 16:08

第一个函数为啥不报错呢?User对象用完应该就被释放了 对以下内容的回复:

EganLi 2020-01-22 10:46
let mut u: &User;
{
  let t = User{age:1};
  u = &t;
}

test2和上面的是等价的,可以看看Rust教程的第10章第3节,借用检查器部分。

这是一条规则,被引用对象要比引用对象有更长的生命周期。这条规则是为了防止垂悬指针的问题。

zyctree 2020-01-21 19:45

第一个 User 是一个常量, 生命周期可以到 'static

下面的代码也能编译通过

fn test1(mut u: &'static User) {
    u = &User { age: 1 };
}
SaylorZhu 2020-01-21 16:54

关注

1 共 9 条评论, 1 页