面试题答案
一键面试Rust 中 str 类型内存布局
- 栈上布局:
str
本身是一个胖指针(fat pointer),在栈上占据 12 个字节(64 位系统)。它由两部分组成:- 指向字符串数据的指针:这部分指向堆上存储的实际字符串内容。
- 字符串的长度:记录字符串的字节长度。
- 堆上布局:实际的字符串内容存储在堆上,以 UTF - 8 编码形式存储。例如字符串
"hello"
,其在堆上存储的是h
(0x68)、e
(0x65)、l
(0x6c)、l
(0x6c)、o
(0x6f)这些 UTF - 8 编码字节序列。
Rust 中 str 类型生命周期管理
- 静态生命周期:当
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
就有效。
借用、所有权转移操作及表现
- 借用操作:
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
类型,将所有权转移给调用者 s1
。get_str
函数返回 &'static str
,由于字符串字面量的 'static
生命周期,调用者 s2
可以直接使用。注意在处理 str
相关操作时,要确保生命周期的正确性,避免悬空指针(dangling pointer)等问题,比如不要返回指向局部变量的 &str
。