Reference 在创建别名可变借用之后但在使用之前使用不可变借用是否确实危险?

Reference 在创建别名可变借用之后但在使用之前使用不可变借用是否确实危险?,reference,rust,borrow-checker,mutability,borrowing,Reference,Rust,Borrow Checker,Mutability,Borrowing,本MCVE: struct A { b: B, } struct B { c: i32, } fn f(_a: &A) {} fn g(_b: &mut B) {} fn main() { let mut foo = A { b: B { c: 2 } }; let bar = &mut foo.b; f(&foo); g(bar); } 导致以下错误: error[E0502]:无法将'foo'作为不可变

本MCVE:

struct A {
    b: B,
}

struct B {
    c: i32,
}

fn f(_a: &A) {}

fn g(_b: &mut B) {}

fn main() {
    let mut foo = A { b: B { c: 2 } };
    let bar = &mut foo.b;
    f(&foo);
    g(bar);
}
导致以下错误:

error[E0502]:无法将'foo'作为不可变项借用,因为它也是作为可变项借用的
-->src/main.rs:16:7
|
15 | let bar=&mut foo.b;
|------可变借用发生在此处
16 | f&foo;
|^^^^此处发生不可变借用
17克(巴);
|---可变借用稍后在此处使用
我理解为什么同时使用可变和不可变的借词是危险的,但是由于
f
不返回任何内容,在使用
bar
时,引用
&foo
就不再使用了。这段代码实际上是危险的,还是编译器的限制?如果是这样的话,写这段代码的惯用方法是什么?我需要用手机吗

这段代码实际上是危险的,还是编译器的限制

嗯。。。这并不危险,因为它不编译


如果它被编译了呢

让我们设想一下,不使用您使用的rustc,而是使用一个Rust-to-C编译器,它假定代码是正确的,并且不执行借用检查

将代码的正确格式副本转换为C:

struct B { int c; };

struct A { struct B b; };

void f(struct A const* a) {}

void g(struct B* restrict b) {}

int main(int argc, char** argv) {
    struct A foo = { { 2 } };
    struct B* restrict bar = &foo.b;
    f(&foo);
    g(bar);
}
注意
restrict
限定符的存在,C相当于
&mut
,它向编译器指示指针没有别名。(我的重点):

在声明受限指针p的块的每次执行期间(通常是p是函数参数的函数体的每次执行),如果通过p(直接或间接)访问的某个对象被修改,则所有对该对象的访问(读和写)在该块中,必须通过P(直接或间接)发生,否则行为未定义

我邀请您检查链接,还有其他几种情况会导致未定义的行为

我不清楚这是否是一个问题,毕竟您不执行任何修改


从C++的经验中,我建议转向模糊的情况:<强>如果不能证明是正确的,那么它是危险的< /强> .< /p>如果使用线程,这将是潜在的危险,这需要更复杂的MCVE。我认为,既然这样做没有什么危险,就没有什么理由在这里使用可变借用,因为这两个函数都使用不可变借用。是不是你把这个例子简化得太多了?@MatthieuM。事实上,我最初的例子有点过于简化了。我更新了它,以便

g
接受可变引用。当然,在我最初的代码
f
g
中确实做了一些事情:)但是正如你所说的,现在还不清楚为什么在调用
f
后使用bar可能会有危险。谢谢,现在更合理了:)我想知道
g
是否要修改
bar.c
,以及
f
打印
foo.bar.c
,如果允许一致性编译器根据
bar
restrict
而对
f
g
的调用重新排序(先修改,后打印),则不存在其他指针。。。无论如何,尽管我认为这个程序会违反拉尔夫·荣格的内存安全模型,实际上,这是保证内存安全的标准。一个假设的优化会破坏非常相似的代码,就是优化
let x=*foo;/*代码不使用x或foo*/;让y=*foo
将最后一条语句替换为
让y=x
。这似乎是一个非常有益的优化(我们可以避免内存访问),但是如果中间的未知代码可以改变Foo指向的,而不提到FoO——恰好在你的例子中——我们有一个问题。除此之外,注意这个问题是不适定的或者至少是误导的。现在这类代码是否危险并不重要,重要的是是否存在一个假设的符合标准的实现,而这类代码是危险的。基于最近的RUSC所做的事情的争论,充其量只是一个滑坡。IMO对此问题的最佳答案是“这并不重要,因为真正重要的是这是否符合规范”。当然,不幸的是,规范仍然是在制品…@RalfJung:我同意规范应该是最重要的;但是,在没有正式规范的情况下,rustc目前的行为是我们所能得到的最好的。这就是我想说的“如果你不能证明它是正确的,那么它是危险的”。