面试题答案
一键面试Rust引用标记的主要设计原则
- 所有权规则:
- 每个值都有一个变量作为其所有者。
- 同一时间内,一个值只能有一个所有者。
- 当所有者离开作用域时,该值将被丢弃。
- 借用规则:
- 同一时间内,要么只能有一个可变引用(
&mut
),要么可以有多个不可变引用(&
),但不能同时存在可变和不可变引用。这是为了避免数据竞争,因为可变引用意味着对数据的写操作,而多个写操作或读写操作同时进行可能导致未定义行为。 - 引用必须总是有效的,不能引用已经被释放的内存,即避免悬垂引用。
- 同一时间内,要么只能有一个可变引用(
避免悬垂引用的示例
fn main() {
let s1 = String::from("hello");
let result = calculate_length(&s1);
println!("The length of '{}' is {}", s1, result);
}
fn calculate_length(s: &str) -> usize {
s.len()
}
在这个例子中,calculate_length
函数接受一个对String
类型数据的不可变引用&str
。这里遵循了引用的设计原则:
- 没有创建对
String
数据的所有权转移,s1
在main
函数中保持所有权。 - 通过不可变引用传递数据给
calculate_length
函数,避免了对String
数据的意外修改。同时,由于calculate_length
函数中没有改变&str
引用的生命周期,s1
在函数调用结束后仍然有效,没有产生悬垂引用。如果在函数calculate_length
中尝试延长引用的生命周期并返回该引用,例如:
// 以下代码会报错
fn incorrect_calculate_length(s: &str) -> &str {
let new_s = s.to_string();
&new_s // new_s在函数结束时会被丢弃,返回的引用将是悬垂引用
}
这段代码会报错,因为new_s
是在函数内部创建的局部变量,当函数结束时new_s
被丢弃,返回的引用就成了悬垂引用,违反了Rust引用必须总是有效的原则。