在Rust中,究竟什么是可变的和不可变的借用?

时间:2017-04-02 10:01:11

标签: reference rust immutability mutable ownership

我坚持使用借用可变的Rust概念:

#[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);
}

当我尝试编译它时,编译器告诉我:

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

我知道有一条关于可变引用的规则:

  

您只能对特定范围内的特定数据提供一个可变引用。

但为什么可以借用rects不能?我如何实现我想要的 - 在函数调用后打印修改后的字符串?

1 个答案:

答案 0 :(得分:2)

在调用具有a可变引用的函数后,您可以打印rect的原因是它返回u32 Copy能够 - {没有'需要限制rect的进一步使用,因为在调用mut_area后不再使用它。

另一方面,mut_string返回对其参数的引用,因此只要half在范围内,可变借用仍然有效。这就是为什么你不能为了s而不可靠地借用println!()

为了实现你的目标,我会在s函数之外改变mut_string(一个稍微不同的名字现在是一个好主意),所以没有可变的借用 - 它的论证可以不变地借用:

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
}