讓我們看到into_iter()
實施the source爲Vec<T>
:
fn into_iter(mut self) -> IntoIter<T> {
unsafe {
let begin = self.as_mut_ptr();
assume(!begin.is_null());
let end = if mem::size_of::<T>() == 0 {
arith_offset(begin as *const i8, self.len() as isize) as *const T
} else {
begin.offset(self.len() as isize) as *const T
};
let cap = self.buf.cap();
mem::forget(self);
IntoIter {
buf: Shared::new(begin),
cap: cap,
ptr: begin,
end: end,
}
}
}
創建IntoIter
迭代招致一些額外的撥款,而不是爲向量的元素;相反,向量的底層內存細節已註冊。 the codemap()
後面怎麼樣?
fn map<B, F>(self, f: F) -> Map<Self, F> where
Self: Sized, F: FnMut(Self::Item) -> B,
{
Map{iter: self, f: f}
}
這裏沒有額外的矢量分配。最後一塊拼圖是collect()
:
fn collect<B: FromIterator<Self::Item>>(self) -> B where Self: Sized {
FromIterator::from_iter(self)
}
這裏沒有答案; the implementation的from_iter()
爲Vec<T>
?
impl<T> FromIterator<T> for Vec<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
<Self as SpecExtend<T, I::IntoIter>>::from_iter(iter.into_iter())
}
}
這是開始看起來像魔術,但也許是相關SpecExtend code將揭示什麼,我們正在尋找:
impl<T, I> SpecExtend<T, I> for Vec<T>
where I: Iterator<Item=T>,
{
default fn from_iter(mut iterator: I) -> Self {
// Unroll the first iteration, as the vector is going to be
// expanded on this iteration in every case when the iterable is not
// empty, but the loop in extend_desugared() is not going to see the
// vector being full in the few subsequent loop iterations.
// So we get better branch prediction.
let mut vector = match iterator.next() {
None => return Vec::new(),
Some(element) => {
let (lower, _) = iterator.size_hint();
let mut vector = Vec::with_capacity(lower.saturating_add(1));
unsafe {
ptr::write(vector.get_unchecked_mut(0), element);
vector.set_len(1);
}
vector
}
};
<Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
vector
}
default fn spec_extend(&mut self, iter: I) {
self.extend_desugared(iter)
}
}
在這段代碼中,我們終於可以看到Vec::new
和Vec::with_capacity
方法稱爲其爲結果向量分配新的空間。
TL; DR:不,不可能移動和修改一個向量而不需要額外的分配。
雖然這是一個關於優化的有趣問題,但請注意,如果您只是爲'i in&mut u {* i + = 1; }'。 –
@PavelStrakhov如果我理解正確,你的代碼大約是我的僞代碼的Rust翻譯,沒有原始的「功能風格」。另外請注意,在我的例子中,'u'不可變。 – jferard