在Rust中,引用如何成为指向指针的指针?

Elf*_*erg 8 rust

今天的Rust之谜来自The Rust Programming Language,第一版的第4.9节.引用和借用的示例有这个例子:

fn main() {
    fn sum_vec(v: &Vec<i32>) -> i32 {
        return v.iter().fold(0, |a, &b| a + b);
    }

    fn foo(v1: &Vec<i32>) -> i32 {
        sum_vec(v1);
    }

    let v1 = vec![1, 2, 3];

    let answer = foo(&v1);
    println!("{}", answer);
}
Run Code Online (Sandbox Code Playgroud)

这看似合理.它打印出"6",这是你所期望如果 vsum_vec是一个C++参考; 它只是一个内存位置的名称,v1我们定义的向量main().

然后我sum_vec用这个替换了身体:

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (*v).iter().fold(0, |a, &b| a + b);
}
Run Code Online (Sandbox Code Playgroud)

它按预期编译和工作.好吧,那不是......完全疯了.编译器试图让我的生活更轻松,我明白了.令人困惑的是,我必须记住这个语言的特定时态,但并不完全是疯狂的.然后我尝试了:

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (**v).iter().fold(0, |a, &b| a + b);
}
Run Code Online (Sandbox Code Playgroud)

它仍然有效!我勒个去?

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (***v).iter().fold(0, |a, &b| a + b);
}
Run Code Online (Sandbox Code Playgroud)

type [i32] cannot be dereferenced.哦,感谢上帝,这是有道理的.但我原本预计会有两次迭代!

拉斯特引用是不是C++"在内存中的另一个地名,"但什么他们?它们也不是指针,关于它们的规则似乎要么是深奥的,要么是高度特殊的.发生了什么,这样一个引用,一个指针和一个指向指针的指针在这里同样运作良好?

She*_*ter 9

规则不是临时的,也不是真正的深奥.检查其类型v和各种解除引用:

fn sum_vec(v: &Vec<i32>) {
    let () = v;
}
Run Code Online (Sandbox Code Playgroud)

你会得到:

  1. v - > &std::vec::Vec<i32>
  2. *v - > std::vec::Vec<i32>
  3. **v - > [i32]

您已经理解的第一个解引用.第二个取消引用是由于这个Deref特点.Vec<T>对...的推论[T].

执行方法查找时,有一组直接的规则:

  1. 如果类型具有方法,请使用它并退出查找.
  2. 如果对该类型的引用具有该方法,请使用它并退出查找.
  3. 如果可以取消引用类型,请执行此操作,然后返回步骤1.
  4. 否则查找失败.

Rust中的引用不是C++"内存中另一个地方的名称".

它们绝对是记忆中一个地方的名字.实际上,它们编译成你知道的相同的C/C++指针.

  • @ElfSternberg不用担心; 它不是真正的"新手".事实上,我会说这个特殊的问题需要有人知道什么指针/引用能够被它混淆.这里主要的棘手问题是Rust提供的人体工程学设计以及他们在引擎盖下做什么. (4认同)