何时取消引用

When to dereference or not

我正在浏览“Rust Book”网站,以便为即将到来的工作面试学习语言。在矢量一章中,有两个代码示例:

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
        println!("{}", i);
    }
}

和:

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
}

现在我想知道,为什么对于第一个样本,当我们将对向量元素 i 的引用传递给:

println!("{}", i);

但是在我们向向量的每个元素添加 50 的示例中,我们必须在添加到 50 之前使用 * 取消引用该元素?

我们为什么不t/can做以下事情:

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
        println!("{}", *i); // why don't we have to dereference before we pass to println!?
    }
}

或:

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        i += 50; // why can't we just add directly to the reference like this?
    }
}

我一定是误解了我读到的内容,但我认为 Rust 能够辨别您何时需要自动取消引用或不需要。我想我不明白为什么我们需要在两个示例中取消引用(或不取消引用)。我提供的两个示例用我想知道的特定代码位进行了注释。

我认为最简单的方法是将第二个示例视为“正常”示例。

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
}

i 是一个 &mut i32 (只有 i32 因为没有什么可以从中推断任何其他整数类型),所以要分配给它你需要取消引用一个 mut i32.

println! 示例是一个“魔术”示例。 println! 将格式化类型,无论它们是按值还是按引用传递。这非常方便,您不希望它(例如)克隆您要打印的每个字符串,然后在应用程序中稍后使用。


编辑:

为了完整起见,这种“魔法”根本不是真正的魔法,而是对语言特性的巧妙运用。 println!(与其他所有进行格式化的标准宏一样,如 panic!format!)使用 formatting machinery from the standard library. This can work with any type that implements the Display trait (or the Debug trait if you use {:?}). And Display has a blanket impl 来实现 Display (Debug 也这样做):

impl<'_, T> Display for &'_ T where
    T: Display + ?Sized, 
{ /* ... */ }

所以任何你可以用值格式化的东西,你也可以用引用格式化。