MST

星途 面试题库

面试题:Rust中str类型的内存布局及生命周期管理

深入探讨Rust中str类型在内存中的布局方式,以及它的生命周期是如何管理的。结合示例说明当涉及到借用、所有权转移等操作时,str类型的表现及注意事项。
35.4万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

Rust 中 str 类型内存布局

  1. 栈上布局str 本身是一个胖指针(fat pointer),在栈上占据 12 个字节(64 位系统)。它由两部分组成:
    • 指向字符串数据的指针:这部分指向堆上存储的实际字符串内容。
    • 字符串的长度:记录字符串的字节长度。
  2. 堆上布局:实际的字符串内容存储在堆上,以 UTF - 8 编码形式存储。例如字符串 "hello",其在堆上存储的是 h(0x68)、e(0x65)、l(0x6c)、l(0x6c)、o(0x6f)这些 UTF - 8 编码字节序列。

Rust 中 str 类型生命周期管理

  1. 静态生命周期:当 str 作为字符串字面量时,它具有 'static 生命周期。例如:
let s: &'static str = "hello";

这里的 "hello" 字符串字面量存储在程序的只读数据段,其生命周期贯穿整个程序运行期间。 2. 动态生命周期:当 str 是从其他数据结构(如 String)借用而来时,其生命周期由借用的来源决定。例如:

let mut s1 = String::from("world");
let s2: &str = &s1;

s2 的生命周期与 s1 相关联,只要 s1 存在,s2 就有效。

借用、所有权转移操作及表现

  1. 借用操作
fn print_str(s: &str) {
    println!("The string is: {}", s);
}

fn main() {
    let s1 = String::from("rust");
    print_str(&s1);
    println!("s1 is still valid: {}", s1);
}

这里 print_str 函数借用了 s1 中的 str 部分。借用期间,s1 的所有权并未转移,所以在 print_str 调用结束后,s1 仍然有效。注意借用规则要求在同一时间内,要么只能有一个可变借用(&mut str),要么可以有多个不可变借用(&str),否则会导致编译错误。 2. 所有权转移str 本身不拥有所有权,它通常是从拥有所有权的类型(如 String)借用而来。但是,当涉及函数返回等情况时,所有权会发生转移。例如:

fn get_string() -> String {
    let s = String::from("transfer");
    s
}

fn get_str() -> &'static str {
    "static string"
}

fn main() {
    let s1 = get_string();
    let s2 = get_str();
}

get_string 函数返回 String 类型,将所有权转移给调用者 s1get_str 函数返回 &'static str,由于字符串字面量的 'static 生命周期,调用者 s2 可以直接使用。注意在处理 str 相关操作时,要确保生命周期的正确性,避免悬空指针(dangling pointer)等问题,比如不要返回指向局部变量的 &str