rust - 为什么 Rust 编译器在使用 Rust 1.31 时可以打破借用规则?

标签 rust borrow-checker borrowing

我正在学习 Rust by Example 并运行来自 the "Alias" page 的代码:

struct Point {
    x: i32,
    y: i32,
    z: i32,
}

fn main() {
    let mut point = Point { x: 0, y: 0, z: 0 };

    {
        let borrowed_point = &point;
        let another_borrow = &point;

        // Data can be accessed via the references and the original owner
        println!(
            "Point has coordinates: ({}, {}, {})",
            borrowed_point.x, another_borrow.y, point.z
        );

        // Error! Can't borrow point as mutable because it's currently
        // borrowed as immutable.
        let mutable_borrow = &mut point;
        println!(
            "Point has coordinates: ({}, {}, {})",
            mutable_borrow.x, mutable_borrow.y, mutable_borrow.z
        );

        let mutable_borrow2 = &mut point;
        println!(
            "Point has coordinates: ({}, {}, {})",
            mutable_borrow2.x, mutable_borrow2.y, mutable_borrow2.z
        );

        // TODO ^ Try uncommenting this line

        // Immutable references go out of scope
    }

    {
        let mutable_borrow = &mut point;

        // Change data via mutable reference
        mutable_borrow.x = 5;
        mutable_borrow.y = 2;
        mutable_borrow.z = 1;

        // Error! Can't borrow `point` as immutable because it's currently
        // borrowed as mutable.
        //let y = &point.y;
        // TODO ^ Try uncommenting this line

        // Error! Can't print because `println!` takes an immutable reference.
        //println!("Point Z coordinate is {}", point.z);
        // TODO ^ Try uncommenting this line

        // Ok! Mutable references can be passed as immutable to `println!`
        println!(
            "Point has coordinates: ({}, {}, {})",
            mutable_borrow.x, mutable_borrow.y, mutable_borrow.z
        );

        // Mutable reference goes out of scope
    }

    // Immutable references to point are allowed again
    let borrowed_point = &point;
    println!(
        "Point now has coordinates: ({}, {}, {})",
        borrowed_point.x, borrowed_point.y, borrowed_point.z
    );
}

Playground

在使用最新的 Rust 编译器夜间构建的 Windows 上运行此代码时,我没有遇到编译错误(rustc 1.31.0-nightly (f99911a4a 2018-10-23))。 Rust Playground 中最新的每晚构建的 Rust 编译器确实提供了预期的编译错误。

这是为什么?为什么 Rust 编译器可以打破借用规则?我如何在本地修复此问题以获得预期的错误?

最佳答案

当您使用 Rust 1.31 创建一个新的 Cargo 项目时,您会自动选择加入 Rust 2018 版:

[package]
name = "example"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
edition = "2018"

这会打开 non-lexical lifetimes ,它启用了一种更智能的借用检查器形式。如果你想要旧的行为,你可以切换回 2015;这将导致您的代码产生预期的错误。不过,我鼓励您继续使用 2018 版。

Rust Playground 提供版本之间的切换:

playground edition switch

Playground 目前默认为 2015 版,在 Rust 1.31 稳定后,Playground 将默认更改为 2018 版。

How I can change this example to provide expected behavior

在 Rust 2018 中你不能。在非词法生命周期之前,Rust 编译器不够智能。代码本身是安全的,但编译器看不到这一点。编译器现在很聪明,所以代码可以编译。没有理由让编译器模式使本质上正确的代码无法编译。

您应该向 Rust by Example 提出问题,让他们知道他们的示例在 Rust 2018 中不再有效。

关于rust - 为什么 Rust 编译器在使用 Rust 1.31 时可以打破借用规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53045978/

相关文章:

rust - 以内容为条件的流行元素

rust - 我可以用借用的元素来改变向量吗?

使用rust :无法移出索引上下文

rust - 糟糕的 Rust 代码优化还是我做得还不够? (欧拉#757)

rust - 我可以在 Rust 中创建一个包含字符串和该字符串切片的结构吗?

rust - 递归类型-生命周期问题

data-structures - 如何在不需要分配给新变量的情况下为链表实现前置?

rust - 特征的生命周期作为返回值

rust - 让 Enumerate 在 Rust 中作为 ExactSizeIterator 工作

error-handling - 如何为自定义错误类型实现 From 特征?