【问题标题】:Why address of pointer doesn't change when modifying the string variable in Rust?为什么修改 Rust 中的字符串变量时指针的地址不会改变?
【发布时间】:2020-03-19 07:21:14
【问题描述】:

我认为 rust 在修改字符串时会在堆内存中生成另一个数据。因此,当我将值推送到字符串变量时,我预计指针地址会发生变化。

fn main() {
    let mut hello = String::from("hello");
    println!("{:?}", hello.as_ptr()); // 0x7fcfa7c01be0
    hello.push_str(", world!");
    println!("{:?}", hello.as_ptr()); // 0x7fcfa7c01be0
}

但是,结果表明并非如此。指针的地址没有改变,所以我用vector类型测试了一下。

fn main() {
    let mut numbers = vec![1, 2, 3];
    println!("{:?}", numbers.as_ptr()); // 0x7ffac4401be0
    numbers.push(4);
    println!("{:?}", numbers.as_ptr()); // 0x7ffac4401ce0
}

向量变量的指针地址在修改时发生了变化。字符串和向量类型的内存有什么区别?

【问题讨论】:

标签: pointers memory rust


【解决方案1】:

String 类似于Vec<T>¹,因为它同时具有length 和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>,这就解释了为什么它们的工作方式相同。

【讨论】:

    【解决方案2】:

    Vec<T> 和 String 可能会保留额外的空间以避免在每次推送操作上分配。这为推送操作提供了平摊的 O(1) 时间。

    vec! 宏可以保证创建一个没有额外空间的向量,而String::from(&str) 没有这样的保证。

    更多详情请见https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-17
      • 2015-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 2019-11-12
      • 1970-01-01
      相关资源
      最近更新 更多