2017-04-02 77 views
1

我坚持用借款可变的锈概念:在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 

我知道有一个规则关于可变参考:

你只能有一个可变的引用特定的pi在特定范围内的数据。

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

回答

2

为什么你可以调用函数与可变引用rect后打印a的原因是,它返回一个u32这是Copy能 - 没有必要限制的rect进一步使用,因为它是mut_area后不再借叫做。

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

为了达到你是什么后,我会变异smut_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 
} 
+0

非常感谢!所以返回的'&str'也是字符串的'&mut'?我可以把'&mut'作为某种“独占锁”给一个变量,当超出范围时会被释放吗? – Melkor

+0

不完全;函数返回的引用是不可变的,尽管你的语句的其余部分是正确的 - 一个可变借入是对借用对象的排他锁。 – ljedrz

+0

明白了。猜猜我必须习惯这些不同的概念,但现在我可以看到基本想法很清楚。 – Melkor