Struct alloc::vec::Vec 1.0.0[−][src]
Expand description
一种连续的可增长数组类型,写成 Vec<T>
,它是 ‘vector’ 的缩写。
Examples
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]);
Runvec!
宏提供方便初始化:
let mut vec1 = vec![1, 2, 3];
vec1.push(4);
let vec2 = Vec::from([1, 2, 3, 4]);
assert_eq!(vec1, vec2);
Run它还可以使用给定值初始化 Vec<T>
的每个元素。
这可能比在单独的步骤中执行分配和初始化更为有效,尤其是在初始化零的 vector 时:
let vec = vec![0; 5];
assert_eq!(vec, [0, 0, 0, 0, 0]);
// 以下是等效的,但可能会更慢:
let mut vec = Vec::with_capacity(5);
vec.resize(5, 0);
assert_eq!(vec, [0, 0, 0, 0, 0]);
Run有关更多信息,请参见 容量和重新分配。
使用 Vec<T>
作为有效的栈:
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() {
// 打印 3、2、1
println!("{}", top);
}
RunIndexing
Vec
类型实现了 Index
trait,因此允许按索引访问值。一个例子将更加明确:
let v = vec![0, 2, 4, 6];
println!("{}", v[1]); // 它将显示 '2'
Run但是要小心:如果您尝试访问 Vec
中没有的索引,则您的软件将为 panic! 您不可以做这个:
let v = vec![0, 2, 4, 6];
println!("{}", v[6]); // 它会 panic!
Run如果要检查索引是否在 Vec
中,请使用 get
和 get_mut
。
Slicing
Vec
可以是可变的。另一方面,切片是只读对象。
要获得 slice,请使用 &
。Example:
fn read_slice(slice: &[usize]) {
// ...
}
let v = vec![0, 1];
read_slice(&v);
// ... 仅此而已!
// 您也可以这样:
let u: &[usize] = &v;
// 或像这样:
let u: &[_] = &v;
Run在 Rust 中,当您只想提供读取访问权限时,将切片作为参数而不是 vectors 传递是更常见的。String
和 &str
也是如此。
容量和重新分配
vector 的容量是为将添加到 vector 上的任何 future 元素分配的空间量。请勿将其与 vector 的长度混淆,后者指定 vector 中的实际元素数量。 如果 vector 的长度超过其容量,则其容量将自动增加,但必须重新分配其元素。
例如,容量为 10 且长度为 0 的 vector 将是一个空的 vector,具有 10 个以上元素的空间。将 10 个或更少的元素压入 vector 不会改变其容量或引起重新分配。
但是,如果 vector 的长度增加到 11,则必须重新分配,这可能会很慢。因此,建议尽可能使用 Vec::with_capacity
来指定 vector 希望达到的大小。
Guarantees
由于其不可思议的基本特性,Vec
为其设计提供了很多保证。这样可以确保它在一般情况下的开销尽可能小,并且可以通过不安全的代码以原始方式正确地进行操作。请注意,这些保证是针对不合格的 Vec<T>
。
如果添加了其他类型参数 (例如,以支持自定义分配器),则覆盖其默认值可能会更改行为。
从根本上讲,Vec
始终是 (指针,容量,长度) 三元组。不多也不少。这些字段的顺序是完全不确定的,您应该使用适当的方法来修改它们。
指针永远不会为空,因此此类型是经过空指针优化的。
但是,指针实际上可能并不指向分配的内存。
特别是,如果您通过 Vec::new
,vec![]
,Vec::with_capacity(0)
或通过在空 Vec 上调用 shrink_to_fit
来构造容量为 0 的 Vec
,则它将不会分配内存。同样,如果将零大小的类型存储在 Vec
内,则不会为它们分配空间。
Note 在这种情况下,Vec
可能不会报告 0 的 capacity
。
当且仅当 mem::size_of::<T>() * capacity() > 0
时,Vec
才会分配。
一般来说,Vec
的分配细节非常微妙 – 如果您打算使用 Vec
分配内存并将其用于其他用途 (或者传递给不安全的代码,或者构建您自己的内存支持集合),请务必使用 from_raw_parts
处理此内存以恢复 Vec
,然后丢弃它来释放此内存。
如果一个 Vec
已分配了内存,那么它指向的内存在堆上(由分配器定义,Rust 被配置为默认使用),它的指针按顺序指向 len
个已初始化的连续元素(如果将其强制转换为切片,您会看到什么),然后是 capacity - len
逻辑上未初始化的连续元素。
包含元素 'a'
和 'b'
且容量为 4 的 vector 可以如下所示。顶部是 Vec
结构体,它包含一个指向堆中分配头,长度和容量的指针。
底部是堆上的分配,即连续的内存块。
ptr len capacity
+--------+--------+--------+
| 0x0123 | 2 | 4 |
+--------+--------+--------+
|
v
Heap +--------+--------+--------+--------+
| 'a' | 'b' | uninit | uninit |
+--------+--------+--------+--------+
- uninit 代表未初始化的内存,请参见
MaybeUninit
。 - Note: ABI 不稳定,并且
Vec
不保证其内存布局 (包括字段顺序)。
Vec
永远不会执行小优化,其中元素实际上存储在栈中,原因有两个:
-
这将使不安全的代码更难以正确操作
Vec
。如果仅移动Vec
的内容,它的地址就不会稳定,因此,确定Vec
是否实际分配了内存将更加困难。 -
这将惩罚一般情况,每次访问都会产生一个额外的分支。
Vec
永远不会自动缩小自己,即使完全为空。这样可以确保不会发生不必要的分配或释放。清空 Vec
,然后将其填充回相同的 len
,将不会引起对分配器的调用。如果您希望释放未使用的内存,请使用 shrink_to_fit
或 shrink_to
。
如果报告的容量足够,push
和 insert
将永远不会 (重新) 分配。如果 len == capacity
,则 push
和 insert
将 (重新) 分配。也就是说,报告的容量是完全准确的,可以信赖。如果需要,它甚至可以用来手动释放 Vec
分配的内存。
批量插入方法 可能 重新分配,即使在没有必要时也是如此。
Vec
不保证在满员时重新分配,或调用 reserve
时有任何特定的增长策略。当前的策略是基本的,使用非恒定增长因子可能是合乎需要的。无论使用哪种策略,当然都可以保证 O(1) 摊销 push
。
vec![x; n]
、vec![a, b, c, d]
和 Vec::with_capacity(n)
都将生产完全符合要求容量的 Vec
。
如果 len == capacity
,(如 vec!
宏的情况),则 Vec<T>
可以与 Box<[T]>
相互转换,而无需重新分配或移动元素。
Vec
不会专门覆盖从中删除的任何数据,也不会专门保留它。它的未初始化内存是它可以使用的临时空间。通常,它只会执行最有效或最容易实现的任何事情。为了安全起见,请勿依赖删除的数据进行擦除。
即使您丢弃了一个 Vec
,它的缓冲区也可能会被另一个分配重用。
即使您先将 Vec
的内存清零,这可能不会实际发生,因为优化器不认为这是一个必须保留的副作用。
但是,有一种情况我们不会中断:使用 unsafe
代码写入多余的容量,然后增加长度以匹配,始终是有效的。
当前,Vec
不保证删除元素的顺序。
顺序过去已更改,并且可能会再次更改。
Implementations
创建一个具有指定容量的新的空 Vec<T>
。
vector 将能够准确地容纳 capacity
元素而无需重新分配。
如果 capacity
为 0,则不会分配 vector。
重要的是要注意,尽管返回的 vector 具有指定的 容量,但 vector 的长度为零。
有关长度和容量之间差异的说明,请参见 容量和重新分配。
Panics
如果新容量超过 isize::MAX
字节,就会出现 panics。
Examples
let mut vec = Vec::with_capacity(10);
// vector 不包含任何项,即使它具有更多功能
assert_eq!(vec.len(), 0);
assert_eq!(vec.capacity(), 10);
// 这些都无需重新分配即可完成...
for i in 0..10 {
vec.push(i);
}
assert_eq!(vec.len(), 10);
assert_eq!(vec.capacity(), 10);
// ... 但是这可能会使 vector 重新分配
vec.push(11);
assert_eq!(vec.len(), 11);
assert!(vec.capacity() >= 11);
Run直接从另一个 vector 的原始组件创建 Vec<T>
。
Safety
这是非常不安全的,因为没有检查的不变量的数量:
-
ptr
需要事先通过String
/Vec<T>
分配 (至少,如果不是,则很可能不正确)。 -
T
需要与ptr
分配的大小和对齐方式相同。 (具有不太严格的对齐方式的T
是不够的,对齐方式实际上必须等于dealloc
的要求,即必须以相同的布局分配和释放内存。) -
length
需要小于或等于capacity
。 -
capacity
需要是分配指针的容量。
违反这些可能会导致一些问题,比如破坏分配器的内部数据结构。例如,从指向长度为 size_t
的 C char
数组的指针构建 Vec<u8>
是不安全的。
从 Vec<u16>
及其长度构建一个也不安全,因为分配器关心对齐方式,并且这两种类型具有不同的对齐方式。
缓冲区的分配是对齐 2 (对于 u16
),但是将其转换为 Vec<u8>
后,它将以对齐 1 释放。
ptr
的所有权有效地转移到 Vec<T>
,然后 Vec<T>
可以随意释放,重新分配或更改指针所指向的内存的内容。
调用此函数后,请确保没有其他任何东西使用该指针。
Examples
use std::ptr;
use std::mem;
let v = vec![1, 2, 3];
// 防止运行 `v` 的析构函数,因此我们可以完全控制分配。
let mut v = mem::ManuallyDrop::new(v);
// Pull 有关 `v` 的各种重要信息
let p = v.as_mut_ptr();
let len = v.len();
let cap = v.capacity();
unsafe {
// 用 4、5、6 覆盖内存
for i in 0..len as isize {
ptr::write(p.offset(i), 4 + i);
}
// 将所有内容放回 Vec
let rebuilt = Vec::from_raw_parts(p, len, cap);
assert_eq!(rebuilt, [4, 5, 6]);
}
Run使用提供的分配器构造具有指定容量的新的空 Vec<T, A>
。
vector 将能够准确地容纳 capacity
元素而无需重新分配。
如果 capacity
为 0,则不会分配 vector。
重要的是要注意,尽管返回的 vector 具有指定的 容量,但 vector 的长度为零。
有关长度和容量之间差异的说明,请参见 容量和重新分配。
Panics
如果新容量超过 isize::MAX
字节,就会出现 panics。
Examples
#![feature(allocator_api)]
use std::alloc::System;
let mut vec = Vec::with_capacity_in(10, System);
// vector 不包含任何项,即使它具有更多功能
assert_eq!(vec.len(), 0);
assert_eq!(vec.capacity(), 10);
// 这些都无需重新分配即可完成...
for i in 0..10 {
vec.push(i);
}
assert_eq!(vec.len(), 10);
assert_eq!(vec.capacity(), 10);
// ... 但是这可能会使 vector 重新分配
vec.push(11);
assert_eq!(vec.len(), 11);
assert!(vec.capacity() >= 11);
Runpub unsafe fn from_raw_parts_in(
ptr: *mut T,
length: usize,
capacity: usize,
alloc: A
) -> Self
pub unsafe fn from_raw_parts_in(
ptr: *mut T,
length: usize,
capacity: usize,
alloc: A
) -> Self
直接从另一个 vector 的原始组件创建 Vec<T, A>
。
Safety
这是非常不安全的,因为没有检查的不变量的数量:
-
ptr
需要事先通过String
/Vec<T>
分配 (至少,如果不是,则很可能不正确)。 -
T
需要与ptr
分配的大小和对齐方式相同。 (具有不太严格的对齐方式的T
是不够的,对齐方式实际上必须等于dealloc
的要求,即必须以相同的布局分配和释放内存。) -
length
需要小于或等于capacity
。 -
capacity
需要是分配指针的容量。
违反这些可能会导致一些问题,比如破坏分配器的内部数据结构。例如,从指向长度为 size_t
的 C char
数组的指针构建 Vec<u8>
是不安全的。
从 Vec<u16>
及其长度构建一个也不安全,因为分配器关心对齐方式,并且这两种类型具有不同的对齐方式。
缓冲区的分配是对齐 2 (对于 u16
),但是将其转换为 Vec<u8>
后,它将以对齐 1 释放。
ptr
的所有权有效地转移到 Vec<T>
,然后 Vec<T>
可以随意释放,重新分配或更改指针所指向的内存的内容。
调用此函数后,请确保没有其他任何东西使用该指针。
Examples
#![feature(allocator_api)]
use std::alloc::System;
use std::ptr;
use std::mem;
let mut v = Vec::with_capacity_in(3, System);
v.push(1);
v.push(2);
v.push(3);
// 防止运行 `v` 的析构函数,因此我们可以完全控制分配。
let mut v = mem::ManuallyDrop::new(v);
// Pull 有关 `v` 的各种重要信息
let p = v.as_mut_ptr();
let len = v.len();
let cap = v.capacity();
let alloc = v.allocator();
unsafe {
// 用 4、5、6 覆盖内存
for i in 0..len as isize {
ptr::write(p.offset(i), 4 + i);
}
// 将所有内容放回 Vec
let rebuilt = Vec::from_raw_parts_in(p, len, cap, alloc.clone());
assert_eq!(rebuilt, [4, 5, 6]);
}
Run将 Vec<T>
分解为其原始组件。
返回指向底层数据的裸指针,vector 的长度 (以元素为单位) 和数据的已分配容量 (以元素为单位)。
这些参数与 from_raw_parts
的参数顺序相同。
调用此函数后,调用者负责 Vec
先前管理的内存。
唯一的方法是使用 from_raw_parts
函数将裸指针,长度和容量转换回 Vec
,从而允许析构函数执行清除操作。
Examples
#![feature(vec_into_raw_parts)]
let v: Vec<i32> = vec![-1, 0, 1];
let (ptr, len, cap) = v.into_raw_parts();
let rebuilt = unsafe {
// 现在,我们可以对组件进行更改,例如将裸指针转换为兼容类型。
let ptr = ptr as *mut u32;
Vec::from_raw_parts(ptr, len, cap)
};
assert_eq!(rebuilt, [4294967295, 0, 1]);
Run将 Vec<T>
分解为其原始组件。
返回指向底层数据的裸指针,vector 的长度 (以元素为单位),数据的已分配容量 (以元素为单位) 以及分配器。
这些参数与 from_raw_parts_in
的参数顺序相同。
调用此函数后,调用者负责 Vec
先前管理的内存。
唯一的方法是使用 from_raw_parts_in
函数将裸指针,长度和容量转换回 Vec
,从而允许析构函数执行清除操作。
Examples
#![feature(allocator_api, vec_into_raw_parts)]
use std::alloc::System;
let mut v: Vec<i32, System> = Vec::new_in(System);
v.push(-1);
v.push(0);
v.push(1);
let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
let rebuilt = unsafe {
// 现在,我们可以对组件进行更改,例如将裸指针转换为兼容类型。
let ptr = ptr as *mut u32;
Vec::from_raw_parts_in(ptr, len, cap, alloc)
};
assert_eq!(rebuilt, [4294967295, 0, 1]);
Run保留最小容量,以便在给定的 Vec<T>
中精确插入 additional
个元素。
调用 reserve_exact
后,容量将大于或等于 self.len() + additional
。
如果容量已经足够,则不执行任何操作。
请注意,分配器可能会给集合提供比其请求更多的空间。
因此,不能依靠容量来精确地最小化。
如果预计将来会插入,则最好使用 reserve
。
Panics
如果新容量超过 isize::MAX
字节,就会出现 panics。
Examples
let mut vec = vec![1];
vec.reserve_exact(10);
assert!(vec.capacity() >= 11);
Run尝试为给 Vec<T>
至少插入 additional
个元素保留容量。
该集合可以保留更多空间,以避免频繁的重新分配。
调用 try_reserve
后,容量将大于或等于 self.len() + additional
。
如果容量已经足够,则不执行任何操作。
Errors
如果容量溢出,或者分配器报告失败,则返回错误。
Examples
use std::collections::TryReserveError;
fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
let mut output = Vec::new();
// 预先保留内存,如果不能,则退出
output.try_reserve(data.len())?;
// 现在我们知道在我们复杂的工作中这不能 OOM
output.extend(data.iter().map(|&val| {
val * 2 + 5 // 非常复杂
}));
Ok(output)
}
Run尝试保留将最小 additional
元素插入给定 Vec<T>
的最小容量。
调用 try_reserve_exact
后,如果返回 Ok(())
,则容量将大于或等于 self.len() + additional
。
如果容量已经足够,则不执行任何操作。
请注意,分配器可能会给集合提供比其请求更多的空间。
因此,不能依靠容量来精确地最小化。
如果希望将来插入,则首选 try_reserve
。
Errors
如果容量溢出,或者分配器报告失败,则返回错误。
Examples
use std::collections::TryReserveError;
fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
let mut output = Vec::new();
// 预先保留内存,如果不能,则退出
output.try_reserve_exact(data.len())?;
// 现在我们知道在我们复杂的工作中这不能 OOM
output.extend(data.iter().map(|&val| {
val * 2 + 5 // 非常复杂
}));
Ok(output)
}
Run缩短 vector,保留前 len
个元素,并丢弃其他元素。
如果 len
大于 vector 的当前长度,则无效。
drain
方法可以模拟 truncate
,但是会导致多余的元素被返回而不是丢弃。
请注意,此方法对 vector 的已分配容量没有影响。
Examples
将五个元素 vector 截断为两个元素:
let mut vec = vec![1, 2, 3, 4, 5];
vec.truncate(2);
assert_eq!(vec, [1, 2]);
Run当 len
大于 vector 的当前长度时,不会发生截断:
let mut vec = vec![1, 2, 3];
vec.truncate(8);
assert_eq!(vec, [1, 2, 3]);
Run在 len == 0
等效于调用 clear
方法时截断。
let mut vec = vec![1, 2, 3];
vec.truncate(0);
assert_eq!(vec, []);
Run返回 vector 的缓冲区的裸指针。
调用者必须确保 vector 比该函数返回的指针寿命更长,否则它将最终指向垃圾。 修改 vector 可能会导致重新分配其缓冲区,这还会使指向该缓冲区的任何指针无效。
调用者还必须确保指针 (non-transitively) 所指向的内存 (从 UnsafeCell
内部除外) 永远不会使用此指针或从其派生的任何指针写入。
如果需要更改切片的内容,请使用 as_mut_ptr
。
Examples
let x = vec![1, 2, 4];
let x_ptr = x.as_ptr();
unsafe {
for i in 0..x.len() {
assert_eq!(*x_ptr.add(i), 1 << i);
}
}
Run返回指向 vector 缓冲区的不安全可变指针。
调用者必须确保 vector 比该函数返回的指针寿命更长,否则它将最终指向垃圾。
修改 vector 可能会导致重新分配其缓冲区,这还会使指向该缓冲区的任何指针无效。
Examples
// 分配足够大的 vector 以容纳 4 个元素。
let size = 4;
let mut x: Vec<i32> = Vec::with_capacity(size);
let x_ptr = x.as_mut_ptr();
// 通过裸指针写入初始化元素,然后设置长度。
unsafe {
for i in 0..size {
*x_ptr.add(i) = i as i32;
}
x.set_len(size);
}
assert_eq!(&*x, &[0, 1, 2, 3]);
Run返回底层分配器的引用。
将 vector 的长度强制为 new_len
。
这是一个低级操作,不维护该类型的任何正常不变量。
通常,使用安全操作之一 (例如 truncate
,resize
,extend
或 clear
) 来更改 vector 的长度。
Safety
new_len
必须小于或等于capacity()
。old_len..new_len
上的元素必须初始化。
Examples
当 vector 用作其他代码的缓冲区时,尤其是在 FFI 上,此方法很有用:
pub fn get_dictionary(&self) -> Option<Vec<u8>> {
// 根据 FFI 方法的文档,32768 字节总是足够的。
let mut dict = Vec::with_capacity(32_768);
let mut dict_length = 0;
// SAFETY: 当 `deflateGetDictionary` 返回 `Z_OK` 时,它认为:
// 1. `dict_length` 元素已初始化。
// 2.
// `dict_length` <= 使 `set_len` 对调用安全的容量 (32_768)。
unsafe {
// 使 FFI 调用...
let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
if r == Z_OK {
// ... 并将长度更新为已初始化的长度。
dict.set_len(dict_length);
Some(dict)
} else {
None
}
}
}
Run尽管下面的示例是正确的,但由于 set_len
调用之前未释放内部 vectors,所以存在内存泄漏:
let mut vec = vec![vec![1, 0, 0],
vec![0, 1, 0],
vec![0, 0, 1]];
// SAFETY:
// 1. `old_len..0` 为空,因此不需要初始化任何元素。
// 2. `0 <= capacity` 无论 `capacity` 是什么,它总是保持不变。
unsafe {
vec.set_len(0);
}
Run通常,在这里,人们将使用 clear
来正确丢弃内容,因此不会泄漏内存。
从 vector 中删除一个元素并返回它。
删除的元素被 vector 的最后一个元素替换。
这不会保留顺序,而是 O(1)。
如果需要保留元素顺序,请改用 remove
。
Panics
如果 index
越界,就会出现 panics。
Examples
let mut v = vec!["foo", "bar", "baz", "qux"];
assert_eq!(v.swap_remove(1), "bar");
assert_eq!(v, ["foo", "qux", "baz"]);
assert_eq!(v.swap_remove(0), "foo");
assert_eq!(v, ["baz", "qux"]);
Run删除并返回 vector 中位置 index
的元素,将其后的所有元素向左移动。
Note: 因为这会转移其余元素,所以它的最坏情况性能为 O(n)。
如果不需要保留元素的顺序,请改用 swap_remove
。
Panics
如果 index
越界,就会出现 panics。
Examples
let mut v = vec![1, 2, 3];
assert_eq!(v.remove(1), 2);
assert_eq!(v, [1, 3]);
Run仅保留谓词指定的元素。
换句话说,删除所有元素 e
,以使 f(&e)
返回 false
。
此方法在原位运行,以原始顺序恰好一次访问每个元素,并保留保留元素的顺序。
Examples
let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
Run由于按原始顺序仅对元素进行过一次访问,因此可以使用外部状态来确定要保留哪些元素。
let mut vec = vec![1, 2, 3, 4, 5];
let keep = [false, true, true, false, true];
let mut iter = keep.iter();
vec.retain(|_| *iter.next().unwrap());
assert_eq!(vec, [2, 3, 5]);
Run移除 vector 中满足给定相等关系的所有连续元素,但第一个除外。
same_bucket
函数被传递给 vector 中的两个元素,并且必须确定这些元素比较是否相等。
元素以与它们在切片中的顺序相反的顺序传递,因此,如果 same_bucket(a, b)
返回 true
,则删除 a
。
如果对 vector 进行了排序,则将删除所有重复项。
Examples
let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
Run创建一个 draining 迭代器,该迭代器删除 vector 中的指定范围并产生删除的项。
当迭代器被丢弃时,该范围内的所有元素都将从 vector 中删除,即使迭代器未被完全消耗。
如果迭代器没有被丢弃 (例如,使用 mem::forget
),则不确定删除了多少个元素。
Panics
如果起点大于终点或终点大于 vector 的长度,就会出现 panics。
Examples
let mut v = vec![1, 2, 3];
let u: Vec<_> = v.drain(1..).collect();
assert_eq!(v, &[1]);
assert_eq!(u, &[2, 3]);
// 全范围清除 vector
v.drain(..);
assert_eq!(v, &[]);
Run在适当位置调整 Vec
的大小,以使 len
等于 new_len
。
如果 new_len
大于 len
,则将 Vec
扩展该差值,并在每个额外的插槽中填充调用闭包 f
的结果。
f
的返回值将按照生成顺序返回到 Vec
。
如果 new_len
小于 len
,则将 Vec
截断。
此方法使用闭包在每次推送时创建新值。如果您希望给定值 Clone
,请使用 Vec::resize
。
如果要使用 Default
trait 生成值,则可以传递 Default::default
作为第二个参数。
Examples
let mut vec = vec![1, 2, 3];
vec.resize_with(5, Default::default);
assert_eq!(vec, [1, 2, 3, 0, 0]);
let mut vec = vec![];
let mut p = 1;
vec.resize_with(4, || { p *= 2; p });
assert_eq!(vec, [2, 4, 8, 16]);
Run消耗并泄漏 Vec
,返回对内容的可变引用,&'a mut [T]
。请注意,类型 T
必须超过所选的生命周期 'a
。
如果类型仅具有静态引用,或者根本没有静态引用,则可以将其选择为 'static
。
从 Rust 1.57 开始,此方法不会重新分配或收缩 Vec
,因此泄漏的分配可能包括不属于返回切片的未使用的容量。
该函数主要用于在程序的剩余生命期内保留的数据。丢弃返回的引用将导致内存泄漏。
Examples
简单用法:
let x = vec![1, 2, 3];
let static_ref: &'static mut [usize] = x.leak();
static_ref[0] += 1;
assert_eq!(static_ref, &[2, 2, 3]);
Run以 MaybeUninit<T>
的切片形式返回 vector 的剩余备用容量。
返回的切片可用于用数据填充 vector (例如
(通过从文件读取) 来标记数据,然后再使用 set_len
方法将其标记为已初始化。
Examples
#![feature(vec_spare_capacity)]
// 分配足够大的 vector 以容纳 10 个元素。
let mut v = Vec::with_capacity(10);
// 填写前 3 个元素。
let uninit = v.spare_capacity_mut();
uninit[0].write(0);
uninit[1].write(1);
uninit[2].write(2);
// 将 vector 的前 3 个元素标记为已初始化。
unsafe {
v.set_len(3);
}
assert_eq!(&v, &[0, 1, 2]);
Run返回 vector 内容作为 T
的切片,以及 vector 的剩余备用容量作为 MaybeUninit<T>
的切片。
返回的备用容量切片可用于在将数据标记为使用 set_len
方法初始化的数据之前 (例如,通过从文件读取) 将数据填充到 vector 中。
请注意,这是一个剧烈的 API,出于优化目的,应谨慎使用。
如果需要将数据追加到 Vec
,则可以根据实际需要使用 push
,extend
,extend_from_slice
,extend_from_within
,insert
,append
,resize
或 resize_with
。
Examples
#![feature(vec_split_at_spare)]
let mut v = vec![1, 1, 2];
// 保留足够大的空间来容纳 10 个元素。
v.reserve(10);
let (init, uninit) = v.split_at_spare_mut();
let sum = init.iter().copied().sum::<u32>();
// 填写接下来的 4 个元素。
uninit[0].write(sum);
uninit[1].write(sum * 2);
uninit[2].write(sum * 3);
uninit[3].write(sum * 4);
// 将 vector 的 4 个元素标记为已初始化。
unsafe {
let len = v.len();
v.set_len(len + 4);
}
assert_eq!(&v, &[1, 1, 2, 4, 8, 12, 16]);
Run在适当位置调整 Vec
的大小,以使 len
等于 new_len
。
如果 new_len
大于 len
,则 Vec
会扩展此差值,每个额外的插槽都将用 value
填充。
如果 new_len
小于 len
,则将 Vec
截断。
为了能够克隆传递的值,此方法需要 T
实现 Clone
。
如果需要更大的灵活性 (或希望依靠 Default
而不是 Clone
),请使用 Vec::resize_with
。
如果您只需要调整到更小的尺寸,请使用 Vec::truncate
。
Examples
let mut vec = vec!["hello"];
vec.resize(3, "world");
assert_eq!(vec, ["hello", "world", "world"]);
let mut vec = vec![1, 2, 3, 4];
vec.resize(2, 0);
assert_eq!(vec, [1, 2]);
Run将元素从 src
复制到 vector 的末尾。
Panics
如果起点大于终点或终点大于 vector 的长度,就会出现 panics。
Examples
let mut vec = vec![0, 1, 2, 3, 4];
vec.extend_from_within(2..);
assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4]);
vec.extend_from_within(..2);
assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]);
vec.extend_from_within(4..8);
assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]);
Run创建一个拼接迭代器,用给定的 replace_with
迭代器替换 vector 中的指定范围,并生成已删除的项。
replace_with
不需要与 range
的长度相同。
即使直到最后才消耗迭代器,range
也会被删除。
如果 Splice
值泄漏,则未指定从 vector 中删除了多少个元素。
输入迭代器 replace_with
只有在 Splice
值被丢弃时才会被消耗。
如果满足以下条件,则为最佳选择:
- 尾部 (
range
之后的 vector 中的元素) 为空, - 或
replace_with
产生的元素少于或等于 ‘range’ 的长度 - 或其
size_hint()
的下界是正确的。
否则,将分配一个临时的 vector 并将尾部移动两次。
Panics
如果起点大于终点或终点大于 vector 的长度,就会出现 panics。
Examples
let mut v = vec![1, 2, 3, 4];
let new = [7, 8, 9];
let u: Vec<_> = v.splice(1..3, new).collect();
assert_eq!(v, &[1, 7, 8, 9, 4]);
assert_eq!(u, &[2, 3]);
Runpub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>ⓘNotable traits for DrainFilter<'_, T, F, A>impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A> where
F: FnMut(&mut T) -> bool, type Item = T;
where
F: FnMut(&mut T) -> bool,
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>ⓘNotable traits for DrainFilter<'_, T, F, A>impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A> where
F: FnMut(&mut T) -> bool, type Item = T;
where
F: FnMut(&mut T) -> bool,
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A> where
F: FnMut(&mut T) -> bool, type Item = T;
创建一个迭代器,该迭代器使用闭包确定是否应删除元素。
如果闭包返回 true,则删除并生成元素。 如果闭包返回 false,则该元素将保留在 vector 中,并且不会由迭代器产生。
使用此方法等效于以下代码:
let mut i = 0;
while i < vec.len() {
if some_predicate(&mut vec[i]) {
let val = vec.remove(i);
// 您的代码在这里
} else {
i += 1;
}
}
Run但是 drain_filter
更易于使用。
drain_filter
也更高效,因为它可以批量回移数组的元素。
请注意,drain_filter
还允许您改变过滤器闭包中的每个元素,无论您选择保留还是删除它。
Examples
将数组拆分为偶数和几率,重新使用原始分配:
#![feature(drain_filter)]
let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
let odds = numbers;
assert_eq!(evens, vec![2, 4, 6, 8, 14]);
assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
RunMethods from Deref<Target = [T]>
对切片进行排序。
这种排序是稳定的 (即,不对相等的元素重新排序),并且 O(n*log(* n*)) 最坏的情况)。
在适用时,首选不稳定排序,因为它通常比稳定排序快,并且不分配辅助内存。
请参见 sort_unstable
。
当前实现
当前的算法是一种受 timsort 启发的自适应迭代合并排序。 在切片几乎被排序或由两个或多个依次连接的排序序列组成的情况下,它设计得非常快。
同样,它分配临时存储空间的大小是 self
的一半,但是对于短片,则使用非分配插入排序。
Examples
let mut v = [-5, 4, 1, -3, 2];
v.sort();
assert!(v == [-5, -3, 1, 2, 4]);
Run用比较器函数对切片进行排序。
这种排序是稳定的 (即,不对相等的元素重新排序),并且 O(n*log(* n*)) 最坏的情况)。
比较器函数必须为切片中的元素定义总顺序。如果排序不全,则元素的顺序是未指定的。
如果一个顺序是 (对于所有的a
, b
和 c
),那么它就是一个总体顺序
- 完全和反对称的:
a < b
,a == b
或a > b
之一正确,并且 - 可传递的,
a < b
和b < c
表示a < c
。==
和>
必须保持相同。
例如,虽然 f64
由于 NaN != NaN
而不实现 Ord
,但是当我们知道切片不包含 NaN
时,可以将 partial_cmp
用作我们的排序函数。
let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
floats.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
Run在适用时,首选不稳定排序,因为它通常比稳定排序快,并且不分配辅助内存。
请参见 sort_unstable_by
。
当前实现
当前的算法是一种受 timsort 启发的自适应迭代合并排序。 在切片几乎被排序或由两个或多个依次连接的排序序列组成的情况下,它设计得非常快。
同样,它分配临时存储空间的大小是 self
的一半,但是对于短片,则使用非分配插入排序。
Examples
let mut v = [5, 4, 1, 3, 2];
v.sort_by(|a, b| a.cmp(b));
assert!(v == [1, 2, 3, 4, 5]);
// 反向排序
v.sort_by(|a, b| b.cmp(a));
assert!(v == [5, 4, 3, 2, 1]);
Run用键提取函数对切片进行排序。
这种排序是稳定的 (即,不对相等的元素重新排序),并且是 O(m* * n ** log(n)) 最坏的情况,其中键函数为 O(m)。
对于昂贵的键函数 (例如
不是简单的属性访问或基本操作的函数),sort_by_cached_key
可能会显着提高速度,因为它不会重新计算元素键。
在适用时,首选不稳定排序,因为它通常比稳定排序快,并且不分配辅助内存。
请参见 sort_unstable_by_key
。
当前实现
当前的算法是一种受 timsort 启发的自适应迭代合并排序。 在切片几乎被排序或由两个或多个依次连接的排序序列组成的情况下,它设计得非常快。
同样,它分配临时存储空间的大小是 self
的一半,但是对于短片,则使用非分配插入排序。
Examples
let mut v = [-5i32, 4, 1, -3, 2];
v.sort_by_key(|k| k.abs());
assert!(v == [1, 2, -3, 4, -5]);
Run用键提取函数对切片进行排序。
在排序期间,键函数每个元素仅被调用一次。
这种排序是稳定的 (即,不对相等的元素重新排序),并且 O(m* * n + n ** log(n)) 最坏的情况是,其中键函数为 O(m)。
对于简单的键函数 (例如,作为属性访问或基本操作的函数),sort_by_key
可能会更快。
当前实现
当前算法基于 Orson Peters 的 pattern-defeating 的快速排序,该算法将随机快速排序的快速平均情况与堆排序的快速最坏情况相结合,同时在具有特定模式的切片上实现了线性时间。 它使用一些随机化来避免退化的情况,但是使用固定的 seed 来始终提供确定性的行为。
在最坏的情况下,该算法在 Vec<(K, usize)>
中分配切片长度的临时存储。
Examples
let mut v = [-5i32, 4, 32, -3, 2];
v.sort_by_cached_key(|k| k.to_string());
assert!(v == [-3, -5, 2, 32, 4]);
Run返回一个 vector,其中包含此切片的副本,其中每个字节都映射到其等效的 ASCII 大写字母。
ASCII 字母 ‘a’ 到 ‘z’ 映射到 ‘A’ 到 ‘Z’,但是非 ASCII 字母不变。
要就地将值大写,请使用 make_ascii_uppercase
。
返回一个 vector,其中包含该切片的副本,其中每个字节均映射为其等效的 ASCII 小写字母。
ASCII 字母 ‘A’ 到 ‘Z’ 映射到 ‘a’ 到 ‘z’,但是非 ASCII 字母不变。
要就地小写该值,请使用 make_ascii_lowercase
。
Trait Implementations
扩展将引用中的元素复制到 Vec 之前的实现。
此实现专用于切片迭代器,它使用 copy_from_slice
一次追加整个切片。
将 BinaryHeap<T>
转换为 Vec<T>
。
这种转换不需要数据移动或分配,并且具有恒定的时间复杂度。
将 Vec<T>
变成 VecDeque<T>
。
这样可以避免在可能的情况下进行重新分配,但是这样做的条件很严格,并且随时可能更改,因此除非 Vec<T>
来自 From<VecDeque<T>>
并且尚未重新分配,否则不应依赖它。
将 Vec<T>
转换为 BinaryHeap<T>
。
此转换发生在原地,并且具有 O(n) 时间复杂度。
将 VecDeque<T>
变成 Vec<T>
。
这永远不需要重新分配,但是如果循环缓冲区恰好不在分配开始时,则确实需要进行 O(n) 数据移动。
Examples
use std::collections::VecDeque;
// 这是 *O*(1)。
let deque: VecDeque<_> = (1..5).collect();
let ptr = deque.as_slices().0.as_ptr();
let vec = Vec::from(deque);
assert_eq!(vec, [1, 2, 3, 4]);
assert_eq!(vec.as_ptr(), ptr);
// 这一项需要重新整理数据。
let mut deque: VecDeque<_> = (1..5).collect();
deque.push_front(9);
deque.push_front(8);
let ptr = deque.as_slices().1.as_ptr();
let vec = Vec::from(deque);
assert_eq!(vec, [8, 9, 1, 2, 3, 4]);
assert_eq!(vec.as_ptr(), ptr);
Run从迭代器创建一个值。 Read more
根据 core::borrow::Borrow
实现的要求,vector 的哈希值与相应的 3 的哈希值相同。
#![feature(build_hasher_simple_hash_one)]
use std::hash::BuildHasher;
let b = std::collections::hash_map::RandomState::new();
let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
let s: &[u8] = &[0xa8, 0x3c, 0x09];
assert_eq!(b.hash_one(v), b.hash_one(s));
Runtype Item = T
type Item = T
被迭代的元素的类型。
如果 Vec<T>
的大小与请求的数组的大小完全匹配,则以数组的形式获取 Vec<T>
的全部内容。
Examples
use std::convert::TryInto;
assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
Run如果长度不匹配,则输入以 Err
返回:
use std::convert::TryInto;
let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
Run如果只需要获得 Vec<T>
的前缀就可以了,您可以先调用 .truncate(N)
。
use std::convert::TryInto;
let mut v = String::from("hello world").into_bytes();
v.sort();
v.truncate(2);
let [a, b]: [_; 2] = v.try_into().unwrap();
assert_eq!(a, b' ');
assert_eq!(b, b'd');
Run