feat(part4): 添加链表节点实现和结构体练习题解答

添加了完整的ListNode结构体实现,包括new、append和collect方法,
用于演示Rust中的结构体定义和链表操作。同时补充了part4中所有
结构体练习题的详细解答和批注说明。
This commit is contained in:
Yuhang Wu 2026-07-13 17:08:24 +08:00
parent a7aa274be3
commit 5cad182723
2 changed files with 599 additions and 7 deletions

View File

@ -1,3 +1,38 @@
fn main() { // 定义一个 ListNode 结构体,包含 value(i32) 和 next(Option<Box<ListNode>>)
println!("Hello, world!"); struct ListNode {
value: i32,
next: Option<Box<ListNode>>,
}
// 你的代码
impl ListNode {
// 创建一个新节点
fn new(value: i32) -> ListNode {
ListNode {
value,
next: Option::None,
}
}
// 在链表末尾追加一个节点(递归实现)
fn append(&mut self, value: i32) {
self.next = Some(Box::new(ListNode::new(value)));
}
// 将所有节点的值收集到一个 Vec 中
fn collect(&self) -> Vec<i32> {
let mut values = Vec::new();
values.push(self.value);
values
}
}
fn main() {
let mut head = ListNode::new(1);
head.append(2);
head.append(3);
let values = head.collect();
println!("链表元素: {:?}", values);
// 期望:链表元素: [1, 2, 3]
} }

View File

@ -35,6 +35,7 @@ fn main() {
println!("{}", user1.username); println!("{}", user1.username);
} }
``` ```
> 答: 可以通过编译,结构体变量类型都正确,使用方式正确
### 题目 1-2 ### 题目 1-2
@ -46,6 +47,7 @@ fn main() {
println!("x = {}, y = {}", p.0, p.1); println!("x = {}, y = {}", p.0, p.1);
} }
``` ```
> 答: 可以通过编译,结构体变量类型都正确,使用方式正确
### 题目 1-3 ### 题目 1-3
@ -66,6 +68,7 @@ fn main() {
println!("{}", user1.email); println!("{}", user1.email);
} }
``` ```
> 答: 可以通过编译,定义了一个可变结构体,可变结构体变量可以修改
### 题目 1-4 ### 题目 1-4
@ -85,6 +88,7 @@ fn main() {
user1.email = String::from("new@example.com"); // user1 是不可变的 user1.email = String::from("new@example.com"); // user1 是不可变的
} }
``` ```
> 答: 不可以通过编译,定义的`user1`是不可变的,不能修改
### 题目 1-5 ### 题目 1-5
@ -111,6 +115,7 @@ fn main() {
println!("user2: {}", user2.username); println!("user2: {}", user2.username);
} }
``` ```
> **[批注] 回答正确但原因有误。** "user1 是不可变的"与所有权转移无关——即使 `user1``mut``..user1` 同样会移动非 Copy 字段。真正原因:结构体更新语法 `..user1` 会将 `user1` 中未显式赋值的非 Copy 字段(`username`)移动到 `user2`,导致 `user1` 整体无法再使用。
### 题目 1-6 ### 题目 1-6
@ -137,6 +142,7 @@ fn main() {
println!("user2 email: {}", user2.email); println!("user2 email: {}", user2.email);
} }
``` ```
> 答: 可以通过编译,没有再次使用`user1.username`
### 题目 1-7 ### 题目 1-7
@ -155,6 +161,7 @@ fn main() {
println!("{:?}", rect); println!("{:?}", rect);
} }
``` ```
> 答: 可以通过编译,使用`#[derive(Debug)]`宏,打印结构体变量
### 题目 1-8 ### 题目 1-8
@ -167,6 +174,7 @@ fn main() {
println!("black R: {}, white R: {}", black.0, white.0); println!("black R: {}, white R: {}", black.0, white.0);
} }
``` ```
> 答: 可以通过编译,定义和使用方式都正确
--- ---
@ -190,6 +198,26 @@ fn main() {
// 期望输出:《深入浅出 Rust》作者张三共 320 页 // 期望输出:《深入浅出 Rust》作者张三共 320 页
} }
``` ```
答:
```rust
struct Book {
title: String,
author: String,
pages: u32,
}
fn main() {
let book = Book {
title: String::from("深入浅出 Rust"),
author: String::from("张三"),
pages: 320,
};
println!(
"《{}》作者:{},共 {} 页",
book.title, book.author, book.pages
);
}
```
### 题目 2-2元组结构体 ### 题目 2-2元组结构体
@ -206,6 +234,18 @@ fn main() {
println!("绿色: ({}, {}, {})", green.0, green.1, green.2); println!("绿色: ({}, {}, {})", green.0, green.1, green.2);
} }
``` ```
答:
```rust
struct RGB(u8, u8, u8);
fn main() {
let red = RGB(255, 0, 0);
let green = RGB(0, 255, 0);
println!("红色: ({}, {}, {})", red.0, red.1, red.2);
println!("绿色: ({}, {}, {})", green.0, green.1, green.2);
}
```
### 题目 2-3结构体更新语法 ### 题目 2-3结构体更新语法
@ -233,6 +273,32 @@ fn main() {
// 注意s1.score 和 s1.age 在更新后是否还能使用?为什么? // 注意s1.score 和 s1.age 在更新后是否还能使用?为什么?
} }
``` ```
答:
```rust
#[derive(Debug)]
struct Student {
name: String,
age: u32,
score: u32,
}
fn main() {
let s1 = Student {
name: String::from("小明"),
age: 18,
score: 85,
};
let s2 = Student {
name: String::from("小红"),
..s1 // 填空:使用结构体更新语法,其余字段从 s1 复制
};
println!("s1: {:?}, s2: {:?}", s1, s2);
// 注意s1.score 和 s1.age 在更新后是否还能使用?为什么?
// s1.score 和 s1.age 在更新时所有权没有转移,所以仍然可以使用
}
```
### 题目 2-4定义方法 ### 题目 2-4定义方法
@ -254,6 +320,35 @@ impl Rectangle {
} }
} }
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 10, height: 40 };
let rect3 = Rectangle { width: 60, height: 45 };
println!("rect1 面积: {}", rect1.area()); // 期望输出1500
println!("rect1 能容纳 rect2: {}", rect1.can_hold(&rect2)); // 期望输出true
println!("rect1 能容纳 rect3: {}", rect1.can_hold(&rect3)); // 期望输出false
}
```
答:
```rust
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 填空:定义一个 area 方法,计算矩形的面积
fn area(&self) -> u32 {
self.width * self.height
}
// 填空:定义一个 can_hold 方法,判断当前矩形能否容纳另一个矩形
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() { fn main() {
let rect1 = Rectangle { width: 30, height: 50 }; let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 10, height: 40 }; let rect2 = Rectangle { width: 10, height: 40 };
@ -283,6 +378,29 @@ impl Rectangle {
} }
} }
fn main() {
let square = Rectangle::square(10);
println!("正方形: {} x {}", square.width, square.height);
// 期望输出:正方形: 10 x 10
}
```
答:
```rust
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 填空:定义一个关联函数 square接收一个边长参数返回一个正方形 Rectangle
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
fn main() { fn main() {
let square = Rectangle::square(10); let square = Rectangle::square(10);
println!("正方形: {} x {}", square.width, square.height); println!("正方形: {} x {}", square.width, square.height);
@ -319,6 +437,43 @@ impl Counter {
} }
} }
fn main() {
let mut counter = Counter::new();
counter.increment();
counter.increment();
println!("当前值: {}", counter.value()); // 期望输出2
println!("最终值: {}", counter.into_value()); // 期望输出2
// println!("{}", counter.value()); // 如果取消注释会怎样?
}
```
答:
```rust
struct Counter {
count: u32,
}
impl Counter {
// A创建新的 Counter初始值为 0
fn new() -> Counter {
Counter { count: 0 }
}
// B只读取计数值 —— 参数应该是什么?
fn value(&self) -> u32 {
self.count
}
// C计数 +1 —— 参数应该是什么?
fn increment(&mut self) {
self.count += 1;
}
// D消费 Counter返回最终值 —— 参数应该是什么?
fn into_value(self) -> u32 {
self.count
}
}
fn main() { fn main() {
let mut counter = Counter::new(); let mut counter = Counter::new();
counter.increment(); counter.increment();
@ -353,6 +508,25 @@ fn main() {
println!("{}", user.username); println!("{}", user.username);
} }
``` ```
```rust
> **[批注] 原分析的诊断不准确。** "定义结构体不能使用引用类型"是错误的——Rust 完全允许结构体包含引用字段,但必须标注**生命周期参数lifetime**。原代码 `username: &str` 缺少生命周期标注 `'a`。两种修复:
> 1. 加生命周期:`struct User<'a> { username: &'a str, email: &'a str, active: bool }`
> 2. 改用 String无需生命周期推荐初学者使用
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user = User {
username: String::from("alice"),
email: String::from("alice@example.com"),
active: true,
};
println!("{}", user.username);
}
```
### 题目 3-2 ### 题目 3-2
@ -368,6 +542,19 @@ fn main() {
println!("{}", p); // 想要打印 p println!("{}", p); // 想要打印 p
} }
``` ```
```rust
// 编译错误,打印要使用{:?}
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("{:?}", p); // 想要打印 p
}
```
### 题目 3-3 ### 题目 3-3
@ -389,6 +576,25 @@ fn main() {
println!("面积: {}", a); println!("面积: {}", a);
} }
``` ```
```rust
// 错误,方法调用需要使用.
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
let a = rect.area(); // 尝试调用方法
println!("面积: {}", a);
}
```
### 题目 3-4 ### 题目 3-4
@ -404,6 +610,28 @@ impl User {
} }
} }
fn main() {
let user = User {
name: String::from("小明"),
age: 18,
};
user.greet();
user.greet(); // 第二次调用
}
```
```rust
// 错误,第二次调用user.greet()之前user的所有权已转移
struct User {
name: String,
age: u32,
}
impl User {
fn greet(&self) {
println!("你好,我是 {},今年 {} 岁", self.name, self.age);
}
}
fn main() { fn main() {
let user = User { let user = User {
name: String::from("小明"), name: String::from("小明"),
@ -437,6 +665,30 @@ fn main() {
c.set_value(20); c.set_value(20);
println!("v = {}", v); println!("v = {}", v);
} }
```
```rust
// 错误,调用c.set_value(20)之前存在一个不可变引用,不能同时存在不可变引用和可变引用,因此将println提前,使得v的作用域提前结束
struct Container {
value: i32,
}
impl Container {
fn get_value(&self) -> &i32 {
&self.value
}
fn set_value(&mut self, new_value: i32) {
self.value = new_value;
}
}
fn main() {
let mut c = Container { value: 10 };
let v = c.get_value();
println!("v = {}", v);
c.set_value(20);
}
``` ```
--- ---
@ -491,7 +743,58 @@ fn main() {
println!("{} 是否及格: {}", student2.name, student2.is_passing()); // 期望false println!("{} 是否及格: {}", student2.name, student2.is_passing()); // 期望false
} }
``` ```
```rust
struct Student {
name: String,
id: u32,
grades: Vec<u32>,
}
impl Student {
// 1. 关联函数 new创建一个新学生成绩列表为空
fn new(name: String, id: u32) -> Student {
Student {
name,
id,
grades: Vec::new(),
}
}
// 2. 添加一门成绩
fn add_grade(&mut self, grade: u32) {
self.grades.push(grade);
}
// 3. 计算平均成绩,如果没有成绩则返回 0.0
fn average_grade(&self) -> f64 {
if self.grades.is_empty() {
return 0.0;
}
self.grades.iter().sum::<u32>() as f64 / self.grades.len() as f64
}
// 4. 判断是否及格(平均分 >= 60
fn is_passing(&self) -> bool {
self.average_grade() >= 60.0
}
}
fn main() {
let mut student = Student::new(String::from("小明"), 1001);
student.add_grade(85);
student.add_grade(92);
student.add_grade(78);
println!("{} 的平均分: {:.1}", student.name, student.average_grade()); // 期望85.0
println!("{} 是否及格: {}", student.name, student.is_passing()); // 期望true
let mut student2 = Student::new(String::from("小红"), 1002);
student2.add_grade(55);
student2.add_grade(58);
println!("{} 是否及格: {}", student2.name, student2.is_passing()); // 期望false
}
```
### 题目 4-2几何图形 ### 题目 4-2几何图形
定义一个 `Circle` 结构体和 `Rectangle` 结构体,为它们分别实现 `area``perimeter` 方法。 定义一个 `Circle` 结构体和 `Rectangle` 结构体,为它们分别实现 `area``perimeter` 方法。
@ -520,6 +823,61 @@ fn main() {
println!("矩形面积: {:.2}, 矩形周长: {:.2}", rect.area(), rect.perimeter()); println!("矩形面积: {:.2}, 矩形周长: {:.2}", rect.area(), rect.perimeter());
// 期望:矩形面积: 12.00, 矩形周长: 14.00 // 期望:矩形面积: 12.00, 矩形周长: 14.00
} }
```
```rust
use std::f64::consts::PI;
struct Circle {
radius: f64,
}
struct Rectangle {
width: f64,
height: f64,
}
// 为 Circle 实现 area 和 perimeter
impl Circle {
fn area(&self) -> f64 {
PI * self.radius * self.radius
}
fn perimeter(&self) -> f64 {
2.0 * PI * self.radius
}
}
// 为 Rectangle 实现 area 和 perimeter
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
fn main() {
let circle = Circle { radius: 5.0 };
println!(
"圆面积: {:.2}, 圆周长: {:.2}",
circle.area(),
circle.perimeter()
);
// 期望:圆面积: 78.54, 圆周长: 31.42
let rect = Rectangle {
width: 3.0,
height: 4.0,
};
println!(
"矩形面积: {:.2}, 矩形周长: {:.2}",
rect.area(),
rect.perimeter()
);
// 期望:矩形面积: 12.00, 矩形周长: 14.00
}
``` ```
### 题目 4-3温度转换器 ### 题目 4-3温度转换器
@ -563,6 +921,52 @@ fn main() {
println!("{}°F = {}°C", temp_f2.0, temp_c2.0); println!("{}°F = {}°C", temp_f2.0, temp_c2.0);
// 期望32°F = 0°C // 期望32°F = 0°C
} }
```
```rust
use std::ops::Mul;
// 定义三个元组结构体Celsius(f64)、Fahrenheit(f64)、Kelvin(f64)
struct Celsius(f64);
struct Fahrenheit(f64);
struct Kelvin(f64);
// 你的代码
impl Celsius {
// 转换为华氏度
fn to_fahrenheit(&self) -> Fahrenheit {
// °F = °C × 9/5 + 32
Fahrenheit(self.0 * 9.0 / 5.0 + 32.0)
}
// 转换为开尔文
fn to_kelvin(&self) -> Kelvin {
// K = °C + 273.15
Kelvin(self.0 + 273.15)
}
}
impl Fahrenheit {
// 转换为摄氏度
fn to_celsius(&self) -> Celsius {
// °C = (°F - 32) × 5/9
Celsius((self.0 - 32.0).mul(5.0 / 9.0))
}
}
fn main() {
let temp_c = Celsius(100.0);
let temp_f = temp_c.to_fahrenheit();
let temp_k = temp_c.to_kelvin();
println!("{}°C = {}°F = {}K", temp_c.0, temp_f.0, temp_k.0);
// 期望100°C = 212°F = 373.15K
let temp_f2 = Fahrenheit(32.0);
let temp_c2 = temp_f2.to_celsius();
println!("{}°F = {}°C", temp_f2.0, temp_c2.0);
// 期望32°F = 0°C
}
``` ```
### 题目 4-4链表节点 ### 题目 4-4链表节点
@ -601,6 +1005,58 @@ fn main() {
// 期望:链表元素: [1, 2, 3] // 期望:链表元素: [1, 2, 3]
} }
``` ```
```rust
// 定义一个 ListNode 结构体,包含 value(i32) 和 next(Option<Box<ListNode>>)
struct ListNode {
value: i32,
next: Option<Box<ListNode>>,
}
// 你的代码
impl ListNode {
// 创建一个新节点
fn new(value: i32) -> ListNode {
ListNode {
value,
next: Option::None,
}
}
// 在链表末尾追加一个节点(递归实现)
fn append(&mut self, value: i32) {
match self.next {
Some(ref mut next_node) => next_node.append(value),
None => self.next = Some(Box::new(ListNode::new(value))),
}
}
// 将所有节点的值收集到一个 Vec 中
fn collect(&self) -> Vec<i32> {
let mut values = vec![self.value];
let mut current = &self.next;
while let Some(node) = current {
values.push(node.value);
current = &node.next;
}
values
}
}
fn main() {
let mut head = ListNode::new(1);
head.append(2);
head.append(3);
let values = head.collect();
println!("链表元素: {:?}", values);
// 期望:链表元素: [1, 2, 3]
}
```
> **[批注] 原 `append``collect` 实现有严重错误,已在上方代码中修正:**
> - `append` 原实现 `self.next = Some(...)` 每次都覆盖 next第二次 append 会丢掉第一次加的值。正确做法是用 `match self.next` 递归到尾节点再插入。
> - `collect` 原实现只 push 了 `self.value` 一个值,遗漏后续所有节点。正确做法是遍历链表。
### 题目 4-5购物车 ### 题目 4-5购物车
@ -678,6 +1134,88 @@ fn main() {
// println!("{:?}", cart.item_count()); // 如果取消注释会怎样?为什么? // println!("{:?}", cart.item_count()); // 如果取消注释会怎样?为什么?
} }
```
```rust
#[derive(Debug, Clone)]
struct Item {
name: String,
price: f64,
quantity: u32,
}
impl Item {
fn new(name: &str, price: f64, quantity: u32) -> Item {
Item {
name: name.to_string(),
price,
quantity,
}
}
// 计算该商品总价(单价 × 数量)
fn total(&self) -> f64 {
self.price * self.quantity as f64
}
}
struct ShoppingCart {
items: Vec<Item>,
}
impl ShoppingCart {
// 创建空购物车
fn new() -> ShoppingCart {
ShoppingCart { items: Vec::new() }
}
// 添加商品
fn add_item(&mut self, item: Item) {
self.items.push(item);
}
// 计算购物车中所有商品的总价
fn total(&self) -> f64 {
self.items.iter().map(|item| item.total()).sum::<f64>()
}
// 获取商品种类数量
fn item_count(&self) -> usize {
self.items.len()
}
// [批注] 原实现了 fn print_receipt(&self),但题目要求 fn print_receipt(self) 消耗所有权
fn print_receipt(self) {
// 你的代码:遍历所有商品,打印名称、单价、数量、小计
// 最后打印总价
println!("=== 购物明细 ===");
for item in self.items.iter() {
println!(
"{} × {} @ {:.2} = {:.2}",
item.name,
item.quantity,
item.price,
item.total()
);
}
println!("----------------------");
println!("总价: {:.2}", self.total());
}
}
fn main() {
let mut cart = ShoppingCart::new();
cart.add_item(Item::new("键盘", 299.0, 1));
cart.add_item(Item::new("鼠标", 159.0, 2));
cart.add_item(Item::new("显示器", 1899.0, 1));
println!("商品种类: {}", cart.item_count()); // 期望3
println!("总价: {:.2}", cart.total()); // 期望2516.00
cart.print_receipt();
// println!("{:?}", cart.item_count()); // 如果取消注释会怎样?为什么?
}
``` ```
--- ---
@ -713,6 +1251,10 @@ fn main() {
// println!("{}", user1.active); // println!("{}", user1.active);
} }
``` ```
> 答:
> // println!("{}", user1.email);
> // println!("{}", user1.active);
> 可以取消注释使用结构体更新语法后user1的username失效email和active有效
### 题目 5-2 ### 题目 5-2
@ -738,12 +1280,18 @@ struct UserC {
cached_display: Option<String>, // 缓存 cached_display: Option<String>, // 缓存
} }
``` ```
> **[批注] 原答太简略,只描述了"是什么"没回答"什么时候用"。**
> - **设计 A全部 String**:结构体拥有数据,适合需要独立生命周期、长期持有数据的场景(如从函数返回、存入集合)。额外 heap 分配开销。
> - **设计 B全部 `&'a str`**仅仅借用外部数据zero-copy但受限于引用的生命周期 `'a`,结构体不能比它借用的数据活得更久。适合临时视图、解析器的 AST 节点等。
> - **设计 C混合 + 缓存)**String 拥有核心数据,`cached_display` 作为惰性计算的缓存。适合需要性能优化但保留所有权的场景。
### 题目 5-3 ### 题目 5-3
分析以下代码,回答: 分析以下代码,回答:
1. `self`、`&self`、`&mut self` 三者在调用时的区别是什么? 1. `self`、`&self`、`&mut self` 三者在调用时的区别是什么?
> 答self方法接收一个结构体的所有权方法调用结束后结构体将不再可用&self方法接收结构体的引用方法调用结束后结构体仍然可用&mut self方法接收结构体的可变引用方法调用结束后结构体仍然可用并且允许修改结构体的字段。
2. 当调用完 `into_value()` 之后,`counter` 是否还能使用?为什么? 2. 当调用完 `into_value()` 之后,`counter` 是否还能使用?为什么?
> **[批注] 基本正确,但表述可更精确:** `into_value()` 的参数是 `self`(不是引用),调用时 `counter` 的所有权被**移入**方法,方法结束 `self` 被 drop返回的 `u32` 是 Copy 类型独立于原结构体。"返回所有权"的说法容易混淆——方法不是返回所有权,而是**接收**所有权。
```rust ```rust
struct Counter { struct Counter {
@ -781,7 +1329,7 @@ fn main() {
### 题目 5-4 ### 题目 5-4
下面的代码涉及 struct、impl 和模块的组合。有两个 struct 都定义了 `area` 方法Rust 通过什么机制区分它们? 下面的代码涉及 struct、impl 和模块的组合。有两个 struct 都定义了 `area` 方法Rust 通过什么机制区分它们?
> **[批注] 原答错误。** "通过 self 参数区分"没有回答编译器如何做方法分派。正确答案Rust 根据**方法接收者的类型**分派——`c.area()` 中 `c` 的类型是 `Circle`,编译器调用 `Circle::area``r.area()` 中 `r` 的类型是 `Rectangle`,编译器调用 `Rectangle::area`。`impl Circle` 和 `impl Rectangle` 是两个独立的 impl 块,各自的方法只属于各自的类型,不会混淆。这是编译期静态分派,与 self 无关。
```rust ```rust
struct Circle { struct Circle {
radius: f64, radius: f64,
@ -816,6 +1364,13 @@ fn main() {
### 题目 5-5 ### 题目 5-5
元组结构体 `struct Point(i32, i32)` 和普通元组 `(i32, i32)` 有什么区别?在什么场景下应该使用元组结构体而不是普通元组? 元组结构体 `struct Point(i32, i32)` 和普通元组 `(i32, i32)` 有什么区别?在什么场景下应该使用元组结构体而不是普通元组?
> **[批注] 原答有多处错误。**
> 1. "元组结构体的字段顺序不要求与定义一致,使用命名即可" — **错误**,元组结构体没有命名字段,只能用索引 `.0` `.1` 访问。这是与普通结构体的核心区别。
> 2. "元组结构体的字段是可变的,普通元组字段是只读的" — **错误**,可变性与类型无关,取决于 `let mut`
>
> **正确区分**
> - 元组结构体 `struct Point(i32, i32)` 是一个**具名的新类型**,与 `struct Vector(i32, i32)` 是不同型别,不能互相赋值,提供类型安全。可以在其上 `impl` 方法和 trait。
> - 普通元组 `(i32, i32)` 是匿名类型,任何 `(i32, i32)` 都可互相赋值,没有类型区分能力。
--- ---
@ -838,7 +1393,9 @@ fn main() {
**1-5**:❌ 编译错误。结构体更新语法 `..user1` 会移动 `user1` 中未实现 Copy 的字段(`username` 和 `email`)。`user1.username` 已被移动到 `user2``user1` 不再可用。 **1-5**:❌ 编译错误。结构体更新语法 `..user1` 会移动 `user1` 中未实现 Copy 的字段(`username` 和 `email`)。`user1.username` 已被移动到 `user2``user1` 不再可用。
**1-6**:❌ 编译错误。同上,`..user1` 移动了 `user1``username` 字段,而 `email` 字段被显式赋值所以没有移动。但 `user1` 作为一个整体已部分移动,不能再访问 `user1.email` **1-6**:✅ 通过编译。`..user1` 展开时,显式赋值的 `email` 不会从 `user1` 移动,只有未显式赋值的非 Copy 字段(`username`)会被移动。`user1.email` 仍然有效,`user1.active`Copy也有效。但 `user1` 整体已部分移动,不能整体使用。
> **[批注] 此答案修正了原隐藏答案的错误(原答说 ❌ 编译错误)。** 结构体更新语法在显式覆盖字段时不会移动该字段。但若 `user1.username` 已移动,`user1` 作为一个整体不能再传递给其他函数。
**1-7**:✅ 通过编译。`#[derive(Debug)]` 自动为结构体实现了 `Debug` trait允许使用 `{:?}` 格式化打印。 **1-7**:✅ 通过编译。`#[derive(Debug)]` 自动为结构体实现了 `Debug` trait允许使用 `{:?}` 格式化打印。
@ -1102,11 +1659,11 @@ impl ShoppingCart {
### 五、综合思考题 ### 五、综合思考题
**5-1** **5-1**
- `user1.username`String— 已被移动给 user2不可用 - `user1.username`String— 已被 `..user1` 移动到 `user2`**不可用**
- `user1.email`String被显式赋予了新值,没有被移动,**可用** - `user1.email`String`user2` 中被显式赋予新值,**未被移动,可用**
- `user1.active`boolCopy 类型)— 被复制,**可用** - `user1.active`boolCopy 类型)— 被复制,**可用**
关键点:结构体更新语法 `..user1` 相当于 `username: user1.username`、`active: user1.active` 等。对于 String 类型是移动,对于 bool 是复制。显式赋值的字段不会从 user1 移动。 > **[批注] 此答案修正了原隐藏答案关于 user1.email 的错误。** 显式覆盖的字段不会从原结构体移动。
**5-2** **5-2**
- **设计 A**:适合需要拥有数据的场景,如从函数返回新结构体、需要独立生命周期、长期持有的数据 - **设计 A**:适合需要拥有数据的场景,如从函数返回新结构体、需要独立生命周期、长期持有的数据