ฉันคิดว่ามีบางอย่างที่จะอธิบายเพิ่มเติมอีกเล็กน้อย ประเภทการเก็บเช่นVec<T>
และVecDeque<T>
มีinto_iter
วิธีการที่อัตราผลตอบแทนเพราะพวกเขาใช้T
IntoIterator<Item=T>
ไม่มีอะไรที่จะหยุดเราจะสร้างประเภทคือFoo<T>
ถ้าซึ่งเป็นซ้ำมากกว่าก็จะให้ผลผลิตไม่ได้แต่อีกประเภทหนึ่งT
U
นั่นคือการดำเนินการFoo<T>
IntoIterator<Item=U>
ในความเป็นจริงมีตัวอย่างบางส่วนstd
: &Path
การดำเนินการ IntoIterator<Item=&OsStr>
และการดำเนินการ&UnixListener
IntoIterator<Item=Result<UnixStream>>
ความแตกต่างระหว่างinto_iter
และiter
กลับไปที่คำถามเดิมกับความแตกต่างระหว่างและinto_iter
iter
คล้ายกับคนอื่น ๆ ที่มีการชี้ความแตกต่างก็คือว่าinto_iter
เป็นวิธีการที่จำเป็นของการIntoIterator
ที่สามารถให้ผลผลิตชนิดใด ๆ IntoIterator::Item
ที่ระบุไว้ใน โดยทั่วไปหากประเภทดำเนินIntoIterator<Item=I>
ตามแบบแผนก็มีสองวิธี ad-hoc: iter
และiter_mut
ที่ผลผลิต&I
และ&mut I
ตามลำดับ
สิ่งที่มันหมายถึงคือเราสามารถสร้างฟังก์ชั่นที่ได้รับประเภทที่มีinto_iter
วิธีการ (เช่นมันเป็น iterable) โดยใช้ลักษณะผูกพัน:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
อย่างไรก็ตามเราไม่สามารถ*ใช้ลักษณะผูกพันที่จะต้องใช้ชนิดที่จะมีiter
วิธีการหรือiter_mut
วิธีการเพราะพวกเขากำลังเพียงการประชุม เราสามารถพูดได้ว่าinto_iter
มีมากขึ้นใช้ได้อย่างกว้างขวางกว่าหรือiter
iter_mut
ทางเลือกเพื่อiter
และiter_mut
ที่น่าสนใจที่จะสังเกตเห็นก็คือว่าiter
ไม่ได้เป็นวิธีเดียวที่จะได้รับการ iterator &T
ที่อัตราผลตอบแทน โดยการประชุม (อีกครั้ง) ประเภทคอลเลกชันSomeCollection<T>
ในstd
ที่มีiter
วิธีการยังมีประเภทของการอ้างอิงที่ไม่เปลี่ยนรูปของพวกเขาดำเนินการ&SomeCollection<T>
IntoIterator<Item=&T>
ตัวอย่างเช่น&Vec<T>
การดำเนินการ IntoIterator<Item=&T>
เพื่อให้เราสามารถทำซ้ำได้มากกว่า&Vec<T>
:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
หากv.iter()
เทียบเท่ากับ&v
ที่ใช้กันทั้งสองIntoIterator<Item=&T>
เหตุใด Rust จึงให้ทั้งสองอย่าง สำหรับการยศาสตร์ ในfor
ลูปก็รัดกุมมากขึ้นอีกนิดกับการใช้งาน&v
กว่าv.iter()
; แต่ในกรณีอื่น ๆv.iter()
มีความชัดเจนมากกว่า(&v).into_iter()
:
let v = vec![1, 2];
let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();
ในทำนองเดียวกันในfor
ลูปv.iter_mut()
สามารถถูกแทนที่ด้วย&mut v
:
let mut v = vec![1, 2];
// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
*item *= 2;
}
เมื่อใดที่จะให้ (ใช้งาน) into_iter
และiter
วิธีการสำหรับประเภท
หากประเภทมี "ทาง" เดียวที่จะวนซ้ำเราควรใช้ทั้งสองอย่าง อย่างไรก็ตามหากมีสองวิธีขึ้นไปสามารถทำซ้ำได้เราควรจัดให้มีวิธีการเฉพาะกิจสำหรับแต่ละวิธี
ตัวอย่างเช่นString
ให้ไม่ใช่into_iter
หรือiter
เพราะมีสองวิธีในการย้ำ: เพื่อย้ำการเป็นตัวแทนในไบต์หรือเพื่อย้ำการเป็นตัวแทนในตัวละคร แต่มีสองวิธี: bytes
สำหรับการทำซ้ำไบต์และchars
สำหรับการทำซ้ำอักขระเป็นทางเลือกแทนiter
วิธีการ
*ทางเทคนิคเราสามารถทำได้โดยการสร้างลักษณะ แต่เราจำเป็นต้องมีคุณสมบัติimpl
นั้นสำหรับแต่ละประเภทที่เราต้องการใช้ ในขณะเดียวกันในหลายประเภทอยู่แล้วดำเนินการstd
IntoIterator