Rust中看似矛盾的借用场景

3
这个Rust程序不能编译,因为b在引用r之前已被释放,这是有道理的:
fn main() {
    let a = "a";
    let v;
    {
        let b = "b";
        v = &b;
    }
    println!("{}", v);
}

在这个第二个 Rust 程序中,通过一个函数获取了对 b 的引用后,突然间就没有问题了:
fn getRef(b: &str) -> &str {
    b
}

fn main() {
    let a = "a";
    let v;
    {
        let b = "b";
        v = getRef(&b);
    }
    println!("{}", v);
}

事实上,v 仍然是指向 b 的引用,但是 b 超出了 println!() 的作用域。
为什么这两者不同呢?

我为了更好的第二个例子进行了修改。 - AaronF
1个回答

5
因为它们没有做同样的事情。
如果你打印变量的类型, 你会发现在第一个例子中,v 的类型是 &&str,具体来说是 & &'static str。而在第二个例子中,v 的类型是 &str,具体来说是 &'static str
在第一个例子中,你有一个对本地值的引用,这确实超出了范围。
在第二个例子中,虽然你引用了b,产生了一个&&str,但随后调用了一个期望一个&str的函数。 Deref coercion 起作用并自动取消引用该值。
因此,第二个例子等价于
fn main() {
    let a = "a";
    let v;
    {
        let b = "b";
        v = b;
    }
    println!("{}", v);
}

也就是说,你正在创建一个不可变引用的副本,该引用指向一个将在整个程序生命周期内存在的字符串。

奇怪 - 所以Rust会自动解引用参数,直到必要的次数?getRef(&&&&&&&&&&&b)可以正常编译。 - Michael Hewson
1
@MichaelHewson 解除引用然后再引用一次。不仅仅是参数,还包括返回值和变量赋值 - Shepmaster
所以 ab 具有相同的生命周期。你可以直接将 b 传递给 getRef() - AaronF
在此过程中不失去所有权? - AaronF
@AaronF 是的,因为不可变引用实现了Copy - Shepmaster
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接