首页 > 解决方案 > 接受字符串引用的函数参数是否直接指向字符串变量或 Rust 堆上的数据

问题描述

我从The Rust Book中拍摄了这张照片和代码。

为什么s指向s1而不只是堆本身的数据?

如果是这样,它是如何工作的?怎么s点到s1。它是否分配了带有 ptr 字段的内存,该字段包含s1. 然后,doess1又指向数据。

s1中,我似乎正在查看一个带有指针、长度和容量的变量。只有ptr字段是这里的实际指针吗?

这是我的第一个系统级语言,所以我认为与 C/C++ 的比较不会帮助我理解这一点。我认为部分问题在于我不太了解指针到底是什么以及操作系统如何分配/取消分配内存。

指针

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

标签: pointersrustreferenceownershipborrowing

解决方案


  • 内存只是一个巨大的数组,可以通过任何偏移量(例如 )来索引u64
  • 这个偏移量称为地址
  • 和一个存储地址的变量,称为指针
  • 但是,通常只分配一小部分内存,因此并非每个地址都是有意义的(或有效的)。
  • 分配是对程序有意义的(顺序)地址范围的请求(因此它可以访问/修改)。
  • 每个对象(我指的是任何类型的对象)都位于分配的内存中(因为未分配的内存对程序毫无意义)。
  • 引用实际上是一个指针,它(由编译器)保证是有效的(即从编译器已知的某个对象的地址派生)。也看看std doc

这里是这些概念的一个例子(操场):

// This is, in real program, implicitly defined,
// but for the sake of example made explicit.
// If you want to play around with the example,
// don't forget to replace `usize::max_value()`
// with a smaller value.
let memory = [uninitialized::<u8>(); usize::max_value()];

// Every value of `usize` type is valid address.
const SOME_ADDR: usize = 1234usize;

// Any address can be safely binded to a pointer,
// which *may* point to both valid and invalid memory.
let ptr: *const u8 = transmute(SOME_ADDR);

// You find an offset in our memory knowing an address
let other_ptr: *const u8 = memory.as_ptr().add(SOME_ADDR);

// Oversimplified allocation, in real-life OS gives a block of memory.
unsafe { *other_ptr = 15; }

// Now it's *meaningful* (i.e. there's no undefined behavior) to make a reference.
let refr: &u8 = unsafe { &*other_ptr };

我希望澄清大多数事情,但让我们明确地涵盖这些问题。

为什么s指向s1而不只是堆本身的数据?

s是一个引用(即有效指针),所以它指向s1. 它可能(并且可能会)被编译器优化为与 相同的内存s1从逻辑上讲,它仍然是指向 的不同对象s1

怎么s点到s1。它是否分配了一个ptr包含内存地址的字段的内存s1

“指向”链仍然存在,因此s.len()在内部调用转换为s.deref().len,并访问转换为的字符串数组的某些字节s.deref().ptr.add(index).deref()

图片上显示了 3 个内存块:&s&s1s1.ptr是不同的(除非优化)内存地址。所有这些都存储在分配的内存中。前两个实际上存储在称为堆栈的预分配(即在调用main函数之前)内存中,通常它不称为已分配内存(尽管我在此答案中忽略了这种做法)。相反,指针指向由用户程序显式分配的内存(即在进入之后)。s1.ptrmain

s1中,我似乎正在查看一个带有指针、长度和容量的变量。只有ptr字段是这里的实际指针吗?

对,就是这样。长度和容量只是常见的无符号整数。


推荐阅读