2016-01-03 13 views
8

Nếu tôi cố gắng để lặp qua một lát hai lần, it works fine:Tại sao tôi có thể lặp qua một lát hai lần, nhưng không phải là một véc-tơ?

let a = &[1, 2, 3]; 
for i in a { 
    println!("{}", i); 
} 
for i in a {   // works fine 
    println!("{}", i); 
} 

Nhưng nếu tôi cố gắng để lặp qua một vector hai lần, it fails:

let a = vec![1, 2, 3]; 
for i in a { 
    println!("{}", i); 
} 
for i in a {   // error: use of moved value: `a` 
    println!("{}", i); 
} 

tôi thấy rằng IntoIterator đặc điểm mất self bởi giá trị, vì vậy nó có ý nghĩa với tôi rằng ví dụ thứ hai thất bại. Nhưng tại sao ví dụ đầu tiên lại thành công?

+1

Về mặt lý thuyết, trong trường hợp đầu tiên, loại 'a' không thực sự là một phần, nó là tham chiếu đến một mảng có độ dài 3. Tuy nhiên, * deref coercions * cho phép tham chiếu đến mảng hoạt động giống như một lát trong hầu hết các trường hợp. – Shepmaster

+0

@Shepmaster cảm ơn vì đã làm rõ. Tôi có nghĩ rằng kiểu 'a' trong ví dụ đầu tiên là '&[i32; 3]', trong khi một lát sẽ là' & [i32] '? Ngoài ra, là sự ép buộc deref bạn đã đề cập có thể nhìn thấy trong [danh sách ở đây] (https://doc.rust-lang.org/std/ops/trait.Deref.html), hoặc là nó huyền diệu hơn? –

+1

Có, đó sẽ là các loại. Tôi đã nói dối một chút, nó là một chút huyền diệu hơn một sự dereference (https://github.com/rust-lang/rust/issues/29993), đó là một * cưỡng chế *. Các tài liệu sẽ được cập nhật sớm với bản sửa lỗi. – Shepmaster

Trả lời

12

Giống như bạn nói, for tác phẩm bằng cách lấy điều bạn hỏi nó để lặp qua, và đi qua nó thông qua IntoIterator::into_iter để tạo ra giá trị iterator thực tế. Cũng như bạn đã nói, into_iter lấy chủ đề theo giá trị.

Vì vậy, khi bạn cố gắng để lặp qua một Vector trực tiếp, điều này có nghĩa là bạn vượt qua toàn bộ vector, bởi giá trị, thành thực hiện IntoIterator của nó, do đó tiêu thụ vector trong quá trình này. Đó là lý do tại sao bạn không thể lặp qua một vectơ một cách trực tiếp hai lần: lặp lại nó lần đầu tiên tiêu thụ nó, sau đó nó không còn tồn tại nữa.

Tuy nhiên, các lát khác nhau: một lát là một con trỏ không thay đổi, được mượn tới dữ liệu của nó; không thể thay đổi, con trỏ mượn có thể được sao chép một cách tự do. Điều này có nghĩa rằng các IntoIterator cho lát bất biến chỉ vay mượn dữ liệu và không tiêu thụ nó (không phải là nó có thể). Hoặc, để xem xét nó theo một cách khác, việc thực hiện IntoIterator của nó chỉ đơn giản là lấy một bản sao của slice, trong khi bạn không thể sao chép Vec.

Cần lưu ý rằng bạn có thể lặp qua một số Vecmà không cần tiêu thụ nó bằng cách lặp lại qua một khoản vay. Nếu bạn kiểm tra documentation for Vec, bạn sẽ lưu ý rằng danh sách triển khai IntoIterator cho Vec<T>, &Vec<T>&mut Vec<T>.

let mut a: Vec<i32> = vec![1, 2, 3]; 

for i in &a {   // iterate immutably 
    let i: &i32 = i; // elements are immutable pointers 
    println!("{}", i); 
} 

for i in &mut a {  // iterate mutably 
    let i: &mut i32 = i;// elements are mutable pointers 
    *i *= 2; 
} 

for i in a {   // iterate by-value 
    let i: i32 = i;  // elements are values 
    println!("{}", i); 
} 

// `a` no longer exists; it was consumed by the previous loop. 
+0

Điều này cực kỳ hữu ích, cảm ơn. Tôi có thể tóm tắt nó theo cách này không? 1) Nếu một kiểu xuất phát từ 'Copy', bạn có thể truyền nó qua một hàm" by value "và vẫn sử dụng nó sau đó, và 2) theo cách kỳ diệu, các slice thực hiện' Copy'. –

+2

@ JackO'Connor, đó là cơ bản chính xác, ngoại trừ có thực sự không có gì huyền diệu trong đó lát thực hiện 'Copy'. Một slice về bản chất là một tham chiếu không thể thay đổi được, và các tham chiếu bất biến được tự nhiên là 'Copy'. –

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