在 Rust 中,为什么可以将更高级别的引用分配给较低级别的引用,为什么不能反过来呢?

In Rust, why can higher-level references be assigned to lower-level references, and why not the other way around?

提问人:Christopher Miller 提问时间:2/7/2023 最后编辑:Christopher Miller 更新时间:2/8/2023 访问量:90

问:

Rust 允许将具有较高间接级别的引用分配给具有较低间接级别的引用。例如,编译器允许将 a 赋值给 :&&&&&&&

fn main() {
    let mut some_number = 5;

    // assign an &&&&&&i32 to an &i32, which works.
    let reference : &i32 = &&&&&&some_number;
}

这也适用于函数参数:

fn main() {
    let num = 5;

    // ref1 is an &&i32
    let ref1 = &#
    
    // Pass an &&i32 to a function parameter, which itself is an &i32 (works)
    func(ref1);
}

fn func(test: &i32) {
    println!("^^^^ This works!");
}

我了解到这是由于自动取消引用而起作用的,它允许 Rust 编译器尽可能多地取消引用类型以匹配其他类型(如果我错了,请纠正我)。

然而,Rust 似乎不允许将低间接引用分配给高间接引用:

fn main() {
    let num = 5;
    
    // Try assigning an &i32 to an &&i32 (error)
    let ref1 : &&i32 = #
}

这会导致编译器错误。在使用函数参数进行测试时,我们得到了类似的编译器错误:expected &i32, found integer

fn main() {
    let num = 5;
    
    // ref1 is an &&&i32
    let ref1 = &&#
    
    // Try passing an &&&i32 to a function parameter of type &&&&&i32 (error)
    func(ref1);
}

fn func(test: &&&&&i32) {
    println!("^^^^^^^^ This does not work!")
}

在这里,我们也得到了一个错误。然而,我很好奇的是,编译器输出并不完全是我们所期望的。编译器错误不是 ,而是 。编译器似乎取消了对两个引用的引用,直到一个不再是引用 - 为什么它取消了对两个引用的引用?我以为它只是取消了对传递给函数的任何内容的引用。mismatched typesexpected &&&&&i32, found &&&i32expected &&i32, found integer

总的来说,我的主要问题是,当允许将较高的间接引用分配给较低的间接引用时,究竟为什么应该不允许将较低的间接性分配给较高的间接性引用?这两件事有什么不同,以至于它们的行为也一定不同?

Rust 逐个引用

评论

0赞 Chayim Friedman 2/8/2023
我投票决定以基于意见的方式结束。为什么编译器输出不同是一个有趣的问题(尽管这并不重要),但我相信您的主要问题无法得到事实的回答。

答:

1赞 cafce25 2/8/2023 #1

&&T可以被强制执行,因为 deref 强制 (“ or to if implements ”) 和 impl Deref<Target = T> for &T 相反,因为不存在 . 通过重复应用可以被强制&T&T&mut T&UTDeref<Target = U>impl Deref<Target = &T> for T&&&&&&T&T

至于为什么一个是允许的,而另一个是不允许的,如果隐式引用在任何地方都允许,跟踪所有权会比现在更难,我们已经在方法接收器的自动引用方面遇到了这个问题。

let s = String::from("Hello");
my_fun(s);

如果不看一下我们是否允许自动引用的定义,就无法回答“是否被移动?”这个问题。smy_fun

评论

0赞 Christopher Miller 2/9/2023
我同意从 to 的隐式引用可能会令人困惑,因为这样用户就不知道变量是否被移动了。但是,我指的是为什么不允许在引用(例如 )之间隐式引用。你能澄清一下吗?i32&i32&&i32&&&&&&i32
1赞 cafce25 2/9/2023
允许后者(通过 )也会自动启用前者。impl Deref<Target = &T> for T