在Rust中,解引用Rc<Vec<T>>容易引起困惑

6
为什么以下代码可以正常工作?
use std::rc::Rc;
fn main () {
    let c = vec![1, 2, 3, 4, 5];
    let r = Rc::new(c);
    println!("{:?}", (**r)[0]);
}

我可以理解单重引用的工作方式(println!("{:?}", (*r)[0]);)。但是双重引用的工作方式我无法理解。


2
解参照陷阱 :) - E net4
2个回答

12

在Rust中,RcVec都实现了Deref,而它的deref方法可以通过*调用。

let c = vec![1, 2, 3, 4, 5];

使用vec!宏创建一个包含给定元素的Vec

let r = Rc::new(c);

从向量创建一个引用计数对象。向量被移动到RC中。

println!("{:?}", (**r)[0]);

这个有点棘手:*r 解引用 Rc,所以我们得到底层的 Vector。*rc 解引用 Vector 作为切片slice[0]索引 切片的第一个元素,其结果是第一个元素1println! 最终打印出结果。


9

如果我们围绕表达式(**r)[0]建立一个函数原型,可能更容易理解发生了什么:

fn foo<T, U>(r: T) -> i32
where
    T: Deref<Target=U>,
    U: Deref<Target=[i32]>,
{
    (**r)[0]
}

Playground

Rc<T>是Rust中大多数智能容器的典型实现,它实现了Deref,以便可以像普通引用一样使用其底层值。反过来,Vec<T>实现了Deref,以便可以将其用作切片(Target = [T])。当执行两次显式解引用*时,会依次应用这两个转换。

当然,通常情况下您不需要这样做,因为Vec还实现了Index运算符。


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