[Rust] Vector có phải là Iterator không?
Hôm nay chúng ta sẽ tìm hiểu về Vector có phải là 1iterator
hay không?.
Xem xét đoạn code sau. It work well!
pub fn run() {
let v1 = vec![1, 2, 3, 4, 5];
for i in v1.iter() {
println!("{i}");
}
for i in v1 {
println!("{i}");
}
}
Nhưng giả sử viết thế này thì sẽ báo lỗi
pub fn run() {
let v1 = vec![1, 2, 3, 4, 5];
for i in v1 {
println!("{i}");
}
for i in v1.iter() { //<--- Error here
println!("{i}");
}
}
Với cảnh báo như sau:
borrow of moved value: `v1`
borrow occurs due to deref coercion to `[i32]`rustcClick for full compiler diagnostic
iterator_test.rs(3, 14): `v1` moved due to this implicit call to `.into_iter()`
iterator_test.rs(2, 9): move occurs because `v1` has type `Vec<i32>`, which does not implement the `Copy` trait
collect.rs(268, 18): `into_iter` takes ownership of the receiver `self`, which moves `v1`
mod.rs(2702, 5): deref defined here
iterator_test.rs(3, 14): consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop: `&`
core::slice
pub fn iter(&self) -> Iter<'_, T>
Giải thích
Tại dòng for i in v1
, thực chất chúng ta đang gọi 1 hàm v1.into_iter()
với đối tương gọi là kiểu Vec<T>
Xem footprint của hàm này:
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> IntoIterator for Vec<T, A> {
type Item = T;
type IntoIter = IntoIter<T, A>;
/// Creates a consuming iterator, that is, one that moves each value out of
/// the vector (from start to end). The vector cannot be used after calling
/// this.
///
/// # Examples
///
/// ```
/// let v = vec!["a".to_string(), "b".to_string()];
/// let mut v_iter = v.into_iter();
///
/// let first_element: Option<String> = v_iter.next();
///
/// assert_eq!(first_element, Some("a".to_string()));
/// assert_eq!(v_iter.next(), Some("b".to_string()));
/// assert_eq!(v_iter.next(), None);
/// ```
#[inline]
fn into_iter(self) -> Self::IntoIter {
unsafe {
let me = ManuallyDrop::new(self);
let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
let buf = me.buf.non_null();
let begin = buf.as_ptr();
let end = if T::IS_ZST {
begin.wrapping_byte_add(me.len())
} else {
begin.add(me.len()) as *const T
};
let cap = me.buf.capacity();
IntoIter { buf, phantom: PhantomData, cap, alloc, ptr: buf, end }
}
}
}
Hàm này nhận vào là self
bị drop
tại let me = ManuallyDrop::new(self);
và trả về một đối tượng mới là IntoIter { buf, phantom: PhantomData, cap, alloc, ptr: buf, end }
Đó là nguyên nhân khi chúng ta sử dụng v1 ở vòng lặp sau không được nữa.
Xem xét khi v1 truyền vào là &'a Vec<'a,T>
thì tình hình lại khác 1 chút
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
Và dưới đây là lời giải thích tốt nhất:
No, a vector is not an iterator.
But it implements the trait IntoIterator, which the for loop uses to convert the vector into the required iterator.
In the documentation for Vec you can see that IntoIterator is implemented in three ways:
- for
Vec<T>
, which is moved and the iterator returns items of typeT
,- for a shared reference
&Vec<T>
, where the iterator returns shared references&T
,- and for
&mut Vec<T>
, where mutable references are returned.iter()
is just a method in Vec to convertVec<T>
directly into an iterator that returns shared references, without first > converting it into a reference. There is a sibling method iter_mut() for producing mutable references.
Happy coding!