我认为在修改字符串时,锈会使堆内存中的另一个数据。因此,我预计当将值推入字符串变量时指针地址会发生变化。
function getRandIndex(arrayLen) {
return Math.floor(Math.random() * arrayLen);
}
function getRandUniqueIndexes(arrayLen, count) {
const indexes = [];
while (indexes.length < count) {
const randIndex = getRandIndex(arrayLen);
if (!indexes.includes(randIndex)) {
indexes.push(randIndex);
}
}
return indexes;
}
// your array with 200 categories
const categories = Array(200).fill(1).map((_, ndx) => `category-${ndx}`);
// array with 20 random unique indexes
const rand20Indexes = getRandUniqueIndexes(categories.length, 20);
console.log(rand20Indexes.map(catIndex => categories[catIndex]));
但是,结果表明不是。指针的地址未更改,因此我使用矢量类型对其进行了测试。
fn main() {
let mut hello = String::from("hello");
println!("{:?}", hello.as_ptr()); // 0x7fcfa7c01be0
hello.push_str(", world!");
println!("{:?}", hello.as_ptr()); // 0x7fcfa7c01be0
}
修改向量变量时,其指针地址已更改。字符串和向量类型的内存有什么区别?
答案 0 :(得分:5)
Vec<T>
和String
可能会保留额外的空间,以避免分配给每个推送操作。这样可以为推送操作提供分摊的O(1)时间。
碰巧的情况是,保证vec!
宏创建的矢量没有这样的额外空间,而String::from(&str)
没有这样的保证。
有关更多详细信息,请参见https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation。
答案 1 :(得分:2)
String
就像Vec<T>
¹,因为它同时具有len
gth和capacity
。如果当前分配的容量足以容纳新字符串,则不需要重新分配基础缓冲区。 The documentation for Vec<T>
explains it this way:
向量的容量是为将添加到向量上的任何将来元素分配的空间量。请勿将其与向量的长度相混淆,后者指定了向量中实际元素的数量。如果向量的长度超过其容量,则其容量将自动增加,但必须重新分配其元素。
例如,容量为10且长度为0的向量将是一个空向量,其空间可容纳10个以上元素。 将10个或更少的元素推入向量不会改变其容量,也不会导致重新分配。
但是,即使容量发生变化,仍然不能保证指针值移动。如果有足够的未分配空间,系统分配器本身可以调整分配大小而无需移动分配。这似乎就是您的代码中正在发生的事情。如果您与指针一起打印容量,则可以观察到此行为:
let mut hello = String::from("hello");
for _ in 0..10 {
println!("({:3}) {:?}", hello.capacity(), hello.as_ptr()); // 0x7fcfa7c01be0
hello.push_str(", world!");
}
( 5) 0x557624d8da40
( 13) 0x557624d8da40
( 26) 0x557624d8dba0
( 52) 0x557624d8dba0
( 52) 0x557624d8dba0
( 52) 0x557624d8dba0
(104) 0x557624d8dba0
(104) 0x557624d8dba0
(104) 0x557624d8dba0
(104) 0x557624d8dba0
在此示例中,缓冲区被调整了4次大小,但内容仅被移动了一次。
¹实际上,String
是新类型的Vec<u8>
,这说明了它们为什么一样工作。