面试题答案
一键面试String
和&str
- 所有权与内存管理
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
也不再有效。
- 场景选择
- 需要修改字符串内容时:使用
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]
- 所有权与内存管理
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
也不再有效。
- 场景选择
- 需要动态修改字节序列时:使用
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 所有权未转移