2015-05-24 16 views
7

Tôi vừa mới viết một chương trình Rust nhỏ tính số Fibonacci và ghi nhớ phép tính. Nó hoạt động, nhưng tôi là một chút bối rối về lý do tại sao, đặc biệt là các cuộc gọi đệ quy. (Nó cũng có thể không phải là thành ngữ.)Tại sao tôi không cần phải cho vay một cách rõ ràng, một biến có thể thay đổi được?

Dưới đây là các chương trình:

use std::collections::HashMap; 

fn main() { 
    let n = 42; // hardcoded for simplicity 
    let mut cache = HashMap::new(); 
    let answer = fib(n, &mut cache); 
    println!("fib of {} is {}", n, answer); 
} 

fn fib(n: i32, cache: &mut HashMap<i32,i32>) -> i32 { 
    if cache.contains_key(&n) { 
     return cache[&n]; 
    } else { 
     if n < 1 { panic!("must be >= 1") } 

     let answer = if n == 1 { 
      0 
     } else if n == 2 { 
      1 
     } else { 
      fib(n - 1, cache) + fib(n - 2, cache) 
     }; 
     cache.insert(n, answer); 
     answer 
    } 
} 

Đây là cách tôi hiểu những gì đang xảy ra:

  • Trong main, let mut cache có nghĩa là "Tôi muốn có thể để thay đổi hashmap này (hoặc gán lại biến) "#:.
  • Khi main gọi fib, thẻ này chuyển số &mut cache để nói "Tôi đang cho bạn mượn điều này và bạn được phép biến đổi nó".
  • Trong chữ ký của fib, cache: &mut Hashmap có nghĩa là "Tôi hy vọng sẽ được vay một HashMap có thể thay đổi - để mượn nó với sự cho phép để đột biến"

(Xin vui lòng sửa cho tôi nếu tôi sai.)

Nhưng khi fib đệ quy, gọi số fib(n -1, cache), tôi không cần sử dụng fib(n -1, &mut cache) và tôi gặp lỗi nếu tôi làm: "không thể mượn biến cục bộ bất biến cache là có thể thay đổi". Huh? Nó không phải là một biến địa phương bất biến, đó là một khoản vay có thể thay đổi - đúng không?

Nếu tôi cố gắng fib(n - 1, &cache), tôi nhận được một lỗi hơi khác nhau:

error: mismatched types: 
expected `&mut std::collections::hash::map::HashMap<i32, i32>`, 
    found `&&mut std::collections::hash::map::HashMap<i32, i32>` 

Mà có vẻ như nó đang nói "Tôi mong đợi một tài liệu tham khảo có thể thay đổi và có một tham chiếu đến một tài liệu tham khảo có thể thay đổi".

Tôi biết rằng fib là cho vay trong cuộc gọi đệ quy vì nếu đã từ bỏ quyền sở hữu, nó không thể gọi cache.insert sau đó. Và tôi biết rằng đây không phải là trường hợp đặc biệt cho đệ quy, bởi vì nếu tôi xác định fib2 để gần giống với fib, tôi có thể yêu cầu họ tái xử lý qua nhau và nó hoạt động tốt.

Tại sao tôi không cần phải cho vay một cách rõ ràng, biến có thể biến đổi?

+0

Bạn có thể chuyển quyền sở hữu và có chức năng trả về một bộ dữ liệu có câu trả lời và bộ nhớ cache: [PlayPen] (http://is.gd/tUadZ0) –

Trả lời

10

Ba điểm của bạn khá nổi bật. Khi trình biên dịch không cho phép bạn vượt qua &mut cache, đó là vì giá trị thực sự đã được vay. Loại cache&mut HashMap<i32, i32>, vì vậy, hãy chuyển qua &mut cache kết quả theo giá trị loại &mut &mut HashMap<i32, i32>. Chỉ cần vượt qua cache kết quả theo loại mong muốn.

Thông báo lỗi cụ thể cannot borrow immutable local variable cache as mutable được kích hoạt do biến số cache không phải là chính nó có thể thay đổi, mặc dù bộ nhớ trỏ đến (HashMap) là. Điều này là do khai báo đối số cache: &mut HashMap<i32, i32> không khai báo biến số mut. Điều này tương tự như cách let khác với tính có thể thay đổi từ số let mut. Rust hỗ trợ các đối số có thể thay đổi, trong trường hợp này sẽ trông giống như mut cache: &mut HashMap<i32, i32>.

+0

Hmm. Tôi không biết tôi có thể có một giá trị biến đổi trong một biến không thay đổi được. Bạn có chắc không? 'let mut cache =' làm cho cả hai có thể thay đổi - có cách nào để khai báo cấu trúc chỉ có thể thay đổi được không? Ngoài ra, nếu tôi thêm 'cache = & mut HashMap :: new();' vào đầu 'fib', tôi gặp lỗi toàn thời gian, nhưng không phải lỗi" bạn không thể gán lại biến này ". –

+0

Ngoài ra: thú vị rằng "đây là một khoản vay có thể thay đổi" được kiểm tra thông qua một loại. Cảm ơn vì đã giúp tôi hiểu. :) –

+0

@NathanLong Bạn thực sự có thể có một tham chiếu có thể thay đổi trong một biến không thay đổi được. Điều này là do Rust chỉ cần tham chiếu có thể thay đổi là duy nhất: không có đoạn mã nào khác có thể đọc hoặc sửa đổi giá trị. Nó là một phần của bộ kiểm tra mượn của trình biên dịch để đảm bảo rằng tất cả '& mut' được đảm bảo là duy nhất (không cần thiết cho' & '). Vì các biến luôn là duy nhất (vì bạn sở hữu chúng) nên tham chiếu '& mut' không thay đổi vẫn là duy nhất và do đó nó có thể được sửa đổi. Bạn cũng có thể xem [this] (https://doc.rust-lang.org/book/references-and-borrowing.html). :) – Snorre

Các vấn đề liên quan