In Rust, what exactly are mutable and immutable borrows?

烈酒焚心 提交于 2020-01-24 13:52:00

问题


I'm stuck with the Rust concepts of borrowing and mutable:

#[derive(Debug)]
struct Rectangle {
    height: u32,
    width: u32,
}

fn mut_area(rect_mut: &mut Rectangle) -> u32 {
    rect_mut.width /= 2;
    rect_mut.height * rect_mut.width
}

fn mut_string(s: &mut String) -> &str {
    s.push_str("!");
    let len = s.len();
    &s[0..len / 2]
}

fn main() {
    let mut rect = Rectangle {
        height: 50,
        width: 40,
    };
    println!("original rect: {:?}", rect);
    let a = mut_area(&mut rect);
    println!("area of rect: {}", a);
    println!("now rect: {:?}", rect);

    let mut s = String::from("helloworld");
    println!("original s: {}", s);
    let half = mut_string(&mut s);
    println!("half of the modified string: {}", half);
    println!("modified s: {}", s);
}

When I tried to compile it, the compiler told me:

error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
  --> <anon>:32:32
   |
30 |     let half = mut_string(&mut s);
   |                                - mutable borrow occurs here
31 |     println!("half of the modified string: {}", half);
32 |     println!("modified s: {}", s);
   |                                ^ immutable borrow occurs here
33 | }
   | - mutable borrow ends here

I know there's a rule about mutable reference:

you can only have one mutable reference to a particular piece of data in a particular scope.

But why can rect be borrowed but s cannot be? And how do I achieve what I want here - to print the modified string after the function call?


回答1:


The reason why you can print a after calling a function with a mutable reference to rect is that it returns a u32 which is Copyable - there is no need to restrict further uses of rect because it is no longer borrowed after mut_area is called.

Your mut_string, on the other hand, returns a reference to its argument, so the mutable borrow remains in force as long as half is in scope. That's why you may not borrow s immutably for the purpose of println!().

In order to achieve what you are after I would mutate s outside of the mut_string function (a slightly different name would be a good idea now) so there is no mutable borrow in force - its argument can be borrowed immutably instead:

fn mut_string(s: &str) -> &str {
    let len = s.len();
    &s[0..len / 2]
}

fn main() {
    let mut rect = Rectangle {
        height: 50,
        width: 40,
    };
    println!("original rect: {:?}", rect);
    let a = mut_area(&mut rect); // rect's mutable borrow expires after this assignment
    println!("area of rect: {}", a);
    println!("now rect: {:?}", rect);

    let mut s = String::from("helloworld");
    println!("original s: {}", s);
    s.push_str("!"); // s is mutated here
    let half = mut_string(&s); // s is borrowed immutably
    println!("half of the modified string: {}", half);
    println!("modified s: {}", s); // another immutable borrow of s
}


来源:https://stackoverflow.com/questions/43167052/in-rust-what-exactly-are-mutable-and-immutable-borrows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!