🦀 Rust 所有权与移动 - 快问快答

测试你对 Rust 所有权系统的理解

10
题目数量
20
预计时间(分钟)
⭐⭐⭐⭐
难度等级
第1题 (判断题)
在 Rust 中,当一个值被移动后,原来的变量就不能再使用了。
正确
错误

答案解析:

答案:正确

当一个值被移动(move)后,原来的变量失去了对该值的所有权,编译器会阻止对原变量的进一步使用,这是 Rust 防止悬垂指针和双重释放的重要机制。

第2题 (选择题)
以下哪种类型实现了 Copy trait,因此赋值时不会发生移动?
String
Vec<i32>
i32
Box<i32>

答案解析:

答案:i32

i32 是基本数据类型,实现了 Copy trait,赋值时会进行复制而不是移动。String、Vec<i32> 和 Box<i32> 都没有实现 Copy trait,赋值时会发生移动。

第3题 (判断题)
借用(borrowing)允许我们在不获取所有权的情况下使用值。
正确
错误

答案解析:

答案:正确

借用(&T 或 &mut T)允许我们创建对值的引用,在不转移所有权的情况下访问和使用值。这是 Rust 所有权系统的核心特性之一。

第4题 (选择题)
在同一作用域中,对于同一个值,以下哪种借用组合是被允许的?
多个可变借用
多个不可变借用
一个可变借用和一个不可变借用
以上都不允许

答案解析:

答案:多个不可变借用

Rust 的借用规则:在同一时间,要么有一个可变借用,要么有任意数量的不可变借用,但不能同时存在。多个不可变借用是安全的,因为它们不会修改数据。

第5题 (简答题)
什么是 Rust 中的"悬垂引用"(dangling reference)?Rust 如何防止悬垂引用?

答案解析:

参考答案:

悬垂引用是指向已被释放内存的引用。Rust 通过生命周期(lifetime)系统防止悬垂引用:编译器确保引用的生命周期不会超过被引用值的生命周期,如果检测到可能的悬垂引用,编译器会报错。

第6题 (选择题)
以下代码中,哪一行会导致编译错误?
let s1 = String::from("hello"); // 第1行 let s2 = s1; // 第2行 println!("{}", s1); // 第3行 println!("{}", s2); // 第4行
第1行
第2行
第3行
第4行

答案解析:

答案:第3行

第2行将 s1 的所有权移动给了 s2,之后 s1 就不能再使用了。第3行尝试使用已被移动的 s1,会导致编译错误:"borrow of moved value"。

第7题 (判断题)
Clone trait 允许我们显式地复制一个值,避免移动语义。
正确
错误

答案解析:

答案:正确

Clone trait 提供了 clone() 方法,允许我们显式地创建值的深拷贝。当我们调用 clone() 时,原值保持有效,新值获得独立的所有权,从而避免了移动语义。

第8题 (选择题)
在函数参数传递中,以下哪种方式不会转移所有权?
按值传递 (fn func(s: String))
按引用传递 (fn func(s: &String))
按可变引用传递 (fn func(s: &mut String))
按引用传递和按可变引用传递都不会

答案解析:

答案:按引用传递和按可变引用传递都不会

按值传递会转移所有权,而按引用传递(&T)和按可变引用传递(&mut T)都只是借用,不会转移所有权,调用者仍然拥有原值。

第9题 (简答题)
解释 Rust 中 Copy 和 Clone 的区别。

答案解析:

参考答案:

Copy 是隐式的、廉价的位复制,只能用于简单类型(如基本数据类型),赋值时自动复制;Clone 是显式的、可能昂贵的深拷贝,需要手动调用 clone() 方法,可以用于复杂类型。Copy 类型的赋值不会发生移动,而非 Copy 类型的赋值会发生移动(除非显式 clone)。

第10题 (选择题)
以下关于 Rust 所有权的描述,哪个是错误的?
每个值在任意时刻都有且仅有一个所有者
当所有者离开作用域时,值会被自动释放
一个值可以同时有多个所有者
赋值和函数调用可能导致所有权转移

答案解析:

答案:一个值可以同时有多个所有者

这是错误的。Rust 所有权的核心规则之一就是每个值在任意时刻都有且仅有一个所有者。如果需要多个"所有者",可以使用 Rc<T> 或 Arc<T> 等智能指针。

🎉
恭喜完成测验!
10/10
你对Rust所有权系统的掌握非常出色!