Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

rust - Why is it possible to have multiple mutable references with static lifetime in same scope

Why can I have multiple mutable references to a static type in the same scope?

My code:

static mut CURSOR: Option<B> = None;

struct B {
    pub field: u16,
}

impl B {
    pub fn new(value: u16) -> B {
        B { field: value }
    }
}

struct A;

impl A {
    pub fn get_b(&mut self) -> &'static mut B {
        unsafe {
            match CURSOR {
                Some(ref mut cursor) => cursor,
                None => {
                    CURSOR= Some(B::new(10));
                    self.get_b()
                }
            }
        }
    }
}

fn main() {
    // first creation of A, get a mutable reference to b and change its field.
    let mut a = A {};
    let mut b = a.get_b();
    b.field = 15;
    println!("{}", b.field);

    // second creation of A, a the mutable reference to b and change its field.
    let mut a_1 = A {};
    let mut b_1 = a_1.get_b();
    b_1.field = 16;
    println!("{}", b_1.field);

    // Third creation of A, get a mutable reference to b and change its field.
    let mut a_2 = A {};
    let b_2 = a_2.get_b();
    b_2.field = 17;
    println!("{}", b_1.field);

    // now I can change them all
    b.field = 1;
    b_1.field = 2;
    b_2.field = 3;
}

I am aware of the borrowing rules

  • one or more references (&T) to a resource,
  • exactly one mutable reference (&mut T).

In the above code, I have a struct A with the get_b() method for returning a mutable reference to B. With this reference, I can mutate the fields of struct B.

The strange thing is that more than one mutable reference can be created in the same scope (b, b_1, b_2) and I can use all of them to modify B.

Why can I have multiple mutable references with the 'static lifetime shown in main()?

My attempt at explaining this is behavior is that because I am returning a mutable reference with a 'static lifetime. Every time I call get_b() it is returning the same mutable reference. And at the end, it is just one identical reference. Is this thought right? Why am I able to use all of the mutable references got from get_b() individually?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There is only one reason for this: you have lied to the compiler. You are misusing unsafe code and have violated Rust's core tenet about mutable aliasing. You state that you are aware of the borrowing rules, but then you go out of your way to break them!

unsafe code gives you a small set of extra abilities, but in exchange you are now responsible for avoiding every possible kind of undefined behavior. Multiple mutable aliases are undefined behavior.

The fact that there's a static involved is completely orthogonal to the problem. You can create multiple mutable references to anything (or nothing) with whatever lifetime you care about:

fn foo() -> (&'static i32, &'static i32, &'static i32) {
    let somewhere = 0x42 as *mut i32;
    unsafe { (&*somewhere, &*somewhere, &*somewhere) }
}

In your original code, you state that calling get_b is safe for anyone to do any number of times. This is not true. The entire function should be marked unsafe, along with copious documentation about what is and is not allowed to prevent triggering unsafety. Any unsafe block should then have corresponding comments explaining why that specific usage doesn't break the rules needed. All of this makes creating and using unsafe code more tedious than safe code, but compared to C where every line of code is conceptually unsafe, it's still a lot better.

You should only use unsafe code when you know better than the compiler. For most people in most cases, there is very little reason to create unsafe code.

A concrete reminder from the Firefox developers:

zoomed in "this tall to use unsafe" sign zoomed out, showing sign is 8+ ft tall


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...