接受字符串引用的函数参数是否直接指向字符串变量或 Rust 中堆上的数据

Does a function parameter that accepts a string reference point directly to the string variable or the data on the heap in Rust

我从 The Rust Book 中截取了这张照片和代码。

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

如果是这样,它是如何工作的? s 如何指向 s1。是不是分配了内存,ptr字段包含s1的内存地址。然后,s1,依次指向数据

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

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

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()
}
  • memory只是一个巨大的数组,可以通过任何偏移量(例如u64)进行索引。
  • 此偏移量称为地址,
  • 和一个存储地址的变量称为 指针
  • 然而,通常只有一小部分内存被分配,所以并不是每个地址都有意义(或有效)。
  • Allocation 是请求使一个(连续的)地址范围对程序有意义(因此它可以access/modify)。
  • 每个对象(我所说的对象是指任何类型)都位于分配的内存中(因为非分配的内存对程序没有意义)。
  • Reference 实际上是一个(由编译器)保证有效的指针(即从编译器已知的某个对象的地址派生)。也看看 std doc

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

// 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 };

我希望能澄清大部分事情,但让我们明确地涵盖问题。

Why does s point to s1 rather than just the data on the heap itself?

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

How does the s point to s1. Is it allocated memory with a ptr field that contains the memory address of s1.

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

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

In s1, I appear to be looking at a variable with a pointer, length, and capacity. Is only the ptr field the actual pointer here?

是的,没错。长度和容量只是普通的无符号整数。