2017-04-02 2 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 

私はルールがあります知っています約mutable reference:

あなたは特定のpiに対して1つの可変参照を持つことができます特定の範囲内のデータのエコー。

しかし、なぜrectは借りることができますが、sはできません。そして、ここで私が望むものを達成するには - 関数呼び出しの後に修正された文字列を出力するのですか?

答えて

2

あなたはrectに可変参照して、関数を呼び出した後aを印刷することができる理由は、それができCopyあるu32を返すことである - それはもはやmut_area後に借りているのでrectの更なる用途を制限する必要はありませんが呼び出されます。

mut_stringは、その引数への参照を返します。したがって、halfが範囲内にある限り、変更可能な借用は有効です。だからprintln!()の目的のためにsを不変に借りることはできません。

の機能の外にsの機能を変更すると(今はちょっと別の名前が良いアイデアになるはずです)、変更可能な借用はありません。その引数は代わりに不変的に借りることができます:

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

関連する問題