我正在浏览"铁 rust 书"网站,为即将到来的求职面试学习语言.在向量一章中,有两个代码示例:

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;
    }
}

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

println!("{}", i);

但在我们给向量的每个元素加50的例子中,我们必须先用*go 引用元素,然后再加50?

为什么我们不能做以下事情:

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?
    }
}

I must have misunderstood what I read, but I thought Rust was able to discern when you need to dereference or not automatically. I guess I don't understand why we need to dereference (or not dereference) in the two samples. The two examples I provided are commented with the specific bits of code I am wondering about.

推荐答案

我认为最简单的方法是,第二个例子是"正常"的例子.

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.这可以用于实现Display特征的任何类型(如果使用{:?},则为Debug特征).Display有一个blanket impl,表示机具Display的所有引用(Debug也这样做):

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

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

Rust相关问答推荐

为什么迭代器上的`. map(...)`的返回类型如此复杂?

如何找到一个数字在二维数组中的位置(S)?

如何实现泛型枚举的`Serde::Desialize`特性

取得本地对象字段的所有权

作为1字节位掩码的布尔值 struct

如何实现Serde::Ser::Error的调试

由于生存期原因,返回引用的闭包未编译

Boxing 如何将数据从堆栈移动到堆?

仅发布工作区的二进制 crate

在 Rust 中忽略 None 值的正确样式

如何保存指向持有引用数据的指针?

当在lambda中通过引用传递时,为什么会出现终身/类型不匹配错误?

如何在 Rust 中显式声明 std::str::Matches<'a, P> ?

我如何取消转义,在 Rust 中多次转义的字符串?

从光标位置旋转精灵

Rust Serde 为 Option:: 创建反序列化器

在单独的线程上运行 actix web 服务器

为什么我可以从读取的可变自引用中移出?

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?

您不能borrow 对只读值的可变引用