當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Rust Vec用法及代碼示例


本文簡要介紹rust語言中 Struct alloc::vec::Vec 的用法。

用法

pub struct Vec<T, A: Allocator = Global> { /* fields omitted */ }

一種連續可增長的數組類型,寫作Vec<T>,發音為'vector'。

例子

let mut vec = Vec::new();
vec.push(1);
vec.push(2);

assert_eq!(vec.len(), 2);
assert_eq!(vec[0], 1);

assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);

vec[0] = 7;
assert_eq!(vec[0], 7);

vec.extend([1, 2, 3].iter().copied());

for x in &vec {
    println!("{}", x);
}
assert_eq!(vec, [7, 1, 2, 3]);

提供 vec! 宏是為了方便初始化:

let mut vec1 = vec![1, 2, 3];
vec1.push(4);
let vec2 = Vec::from([1, 2, 3, 4]);
assert_eq!(vec1, vec2);

它還可以使用給定值初始化Vec<T> 的每個元素。這可能比在單獨的步驟中執行分配和初始化更有效,尤其是在初始化零向量時:

let vec = vec![0; 5];
assert_eq!(vec, [0, 0, 0, 0, 0]);

// The following is equivalent, but potentially slower:
let mut vec = Vec::with_capacity(5);
vec.resize(5, 0);
assert_eq!(vec, [0, 0, 0, 0, 0]);

有關詳細信息,請參閱容量和重新分配。

使用 Vec<T> 作為高效堆棧:

let mut stack = Vec::new();

stack.push(1);
stack.push(2);
stack.push(3);

while let Some(top) = stack.pop() {
    // Prints 3, 2, 1
    println!("{}", top);
}

索引

Vec 類型允許按索引訪問值,因為它實現了 Index 特征。一個例子會更明確:

let v = vec![0, 2, 4, 6];
println!("{}", v[1]); // it will display '2'

但要小心:如果您嘗試訪問不在 Vec 中的索引,您的軟件將會出現Panics!你不可以做這個:

let v = vec![0, 2, 4, 6];
println!("{}", v[6]); // it will panic!

如果要檢查索引是否在 Vec 中,請使用 get get_mut

切片

Vec 可以是可變的。另一方麵,切片是隻讀對象。要獲得 slice ,請使用 & 。例子:

fn read_slice(slice: &[usize]) {
    // ...
}

let v = vec![0, 1];
read_slice(&v);

// ... and that's all!
// you can also do it like this:
let u: &[usize] = &v;
// or like this:
let u: &[_] = &v;

在 Rust 中,當您隻想提供讀取訪問權限時,將切片作為參數而不是向量傳遞更為常見。 String &str 也是如此。

容量和重新分配

向量的容量是為將添加到向量上的任何未來元素分配的空間量。不要與向量的長度混淆,向量的長度指定向量中實際元素的數量。如果一個向量的長度超過了它的容量,它的容量會自動增加,但它的元素必須重新分配。

例如,容量為 10 且長度為 0 的向量將是一個空向量,其空間可容納 10 個以上的元素。將 10 個或更少的元素推送到向量上不會改變其容量或導致發生重新分配。但是,如果向量的長度增加到 11,則必須重新分配,這可能會很慢。出於這個原因,建議盡可能使用 Vec::with_capacity 來指定向量的預期大小。

保證

由於其令人難以置信的基本性質,Vec 對其設計做出了很多保證。這確保它在一般情況下盡可能為low-overhead,並且可以通過不安全的代碼以原始方式正確操作。請注意,這些保證是指不合格的 Vec<T> 。如果添加了額外的類型參數(例如,支持自定義分配器),覆蓋它們的默認值可能會改變行為。

最根本的是,Vec 是並且永遠都是(指針、容量、長度)三元組。不多也不少。這些字段的順序是完全未指定的,您應該使用適當的方法來修改它們。指針永遠不會為空,所以這個類型是null-pointer-optimized。

但是,指針可能實際上並不指向分配的內存。特別是,如果您構建一個Vec容量為 0 通過Vec::new,alloc::vec,alloc::vec::Vec.with_capacity,或通過調用alloc::vec::Vec.shrink_to_fit在一個空的 Vec 上,它不會分配內存。同樣,如果您將零大小的類型存儲在Vec,它不會為它們分配空間。請注意,在這種情況下,Vec 可能不會報告 capacity 為 0.Vec當且僅當mem::size_of::<T>() * capacity() > 0.一般來說,Vec的分配細節非常微妙——如果你打算使用Vec並將其用於其他用途(傳遞給不安全的代碼,或構建您自己的memory-backed 集合),請務必使用from_raw_parts恢複Vec然後放下它。

如果一個Vec 分配的內存,那麽它指向的內存在堆上(由分配器定義,Rust 配置為默認使用),它的指針指向len按順序初始化的連續元素(如果將其強製為切片,您會看到什麽),然後是capacity - len邏輯上未初始化的連續元素。

包含元素 'a''b' 且容量為 4 的向量可以如下所示進行可視化。頂部是Vec 結構,它包含指向堆中分配頭的指針、長度和容量。底部是堆上的分配,一個連續的內存塊。

ptr      len  capacity
       +--------+--------+--------+
       | 0x0123 |      2 |      4 |
       +--------+--------+--------+
            |
            v
Heap   +--------+--------+--------+--------+
       |    'a' |    'b' | uninit | uninit |
       +--------+--------+--------+--------+
  • 初始化表示未初始化的內存,請參見MaybeUninit.
  • 注意:ABI 不穩定,Vec 不保證其內存布局(包括字段的順序)。

Vec 永遠不會執行 “small optimization” 其中元素實際存儲在堆棧中的原因有兩個:

  • 這將使不安全代碼更難以正確操作 Vec 。如果僅移動Vec 的內容,則它的內容將沒有穩定的地址,並且很難確定Vec 是否實際分配了內存。

  • 它會懲罰一般情況,每次訪問都會產生一個額外的分支。

Vec 永遠不會自動收縮自身,即使完全為空。這確保不會發生不必要的分配或釋放。清空 Vec 然後將其填充回相同的 len 應該不會調用分配器。如果您想釋放未使用的內存,請使用 shrink_to_fit shrink_to

alloc::vec::Vec.pushalloc::vec::Vec.insert如果報告的容量足夠,則永遠不會(重新)分配。alloc::vec::Vec.pushalloc::vec::Vec.insert 將要(重新)分配如果len == capacity.也就是說,報告的容量是完全準確的,並且可以依賴。它甚至可以用於手動釋放由Vec如果需要的話。批量插入方法可能重新分配,即使沒有必要。

Vec不保證任何特定的增長策略在重新分配時已滿,也不保證任何特定的增長策略alloc::vec::Vec.reserve叫做。當前的策略是基本的,並且可能證明使用非恒定增長因子是可取的。無論使用什麽策略,當然都會保證O(1)攤銷alloc::vec::Vec.push.

vec![x; n]vec![a, b, c, d] Vec::with_capacity(n) 都將生成具有完全請求容量的 Vec。如果 len == capacity ,(如 vec! 宏的情況),則可以將 Vec<T> 轉換為 Box<[T]> 和從 Box<[T]> 轉換,而無需重新分配或移動元素。

Vec 不會專門覆蓋從中刪除的任何數據,但也不會專門保留它。其未初始化的內存是臨時空間,它可以隨意使用。它通常隻會做最有效或最容易實現的事情。請勿出於安全目的而依賴刪除已刪除的數據。即使您刪除 Vec ,其緩衝區也可能會被另一個分配重用。即使您首先將 Vec 的內存清零,實際上也可能不會發生,因為優化器不認為這是必須保留的副作用。不過,有一種情況我們不會打破:使用unsafe代碼寫入多餘的容量,然後增加長度以匹配,總是有效的。

目前,Vec 不保證刪除元素的順序。順序過去已更改,可能會再次更改。

相關用法


注:本文由純淨天空篩選整理自rust-lang.org大神的英文原創作品 Struct alloc::vec::Vec。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。