MST

星途 面试题库

面试题:Rust字符串和字节串在内存管理上的差异

详细阐述Rust中`String`和`&str`以及`Vec<u8>`和`&[u8]`在内存管理方面的不同。例如,它们的所有权是如何转移的,内存分配和释放机制有何区别?结合具体代码示例说明在不同场景下如何选择使用以优化内存使用。
21.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

String&str

  1. 所有权与内存管理
    • String
      • 所有权String 拥有它所包含的字符串数据的所有权。当 String 离开作用域时,它会自动释放其所占的内存。
      • 内存分配与释放String 在堆上分配内存来存储字符串数据。其内存大小会根据字符串内容动态变化。例如:
let s1 = String::from("hello");
// s1 拥有 "hello" 数据的所有权,数据存储在堆上

s1 离开作用域时,Rust 的自动内存管理机制会释放堆上存储 "hello" 的内存。

  • &str
    • 所有权&str 是字符串切片,它不拥有数据的所有权,而是借用已存在的字符串数据。&str 通常指向 String 或字符串字面量。
    • 内存分配与释放:它不负责内存的分配与释放,因为它只是一个指向已有数据的引用。例如:
let s1 = String::from("world");
let s2: &str = &s1;
// s2 借用 s1 的数据,不拥有所有权

s2 只是指向 s1 所拥有的堆上数据,当 s1 离开作用域被释放时,s2 也不再有效。

  1. 场景选择
    • 需要修改字符串内容时:使用 String。例如:
let mut s = String::from("rust");
s.push_str(" is great");
  • 只需要读取字符串内容时:使用 &str,因为它不拥有所有权,可用于函数参数以避免所有权转移。例如:
fn print_str(s: &str) {
    println!("The string is: {}", s);
}
let s = String::from("example");
print_str(&s);
// s 所有权未转移

Vec<u8>&[u8]

  1. 所有权与内存管理
    • Vec<u8>
      • 所有权Vec<u8> 拥有它所包含的字节数据的所有权。当 Vec<u8> 离开作用域时,会自动释放堆上存储的字节数据。
      • 内存分配与释放Vec<u8> 在堆上分配内存来存储字节序列,其大小可以动态增长。例如:
let mut v = Vec::new();
v.push(1);
v.push(2);
// v 拥有堆上存储的 [1, 2] 字节数据的所有权

v 离开作用域时,堆上存储字节数据的内存被释放。

  • &[u8]
    • 所有权&[u8] 是字节切片,它不拥有数据的所有权,只是借用已存在的字节序列。它可以指向 Vec<u8> 或静态字节数组。
    • 内存分配与释放:它不负责内存的分配与释放,仅作为引用指向已有数据。例如:
let v = vec![3, 4];
let slice: &[u8] = &v;
// slice 借用 v 的数据,不拥有所有权

v 离开作用域被释放时,slice 也不再有效。

  1. 场景选择
    • 需要动态修改字节序列时:使用 Vec<u8>。例如:
let mut data = Vec::new();
data.extend_from_slice(b"hello");
  • 只需要读取字节序列内容时:使用 &[u8],用于函数参数可避免所有权转移。例如:
fn process_bytes(b: &[u8]) {
    // 处理字节数据
}
let data = vec![10, 20];
process_bytes(&data);
// data 所有权未转移