feat(part4): 添加链表节点实现和结构体练习题解答
添加了完整的ListNode结构体实现,包括new、append和collect方法, 用于演示Rust中的结构体定义和链表操作。同时补充了part4中所有 结构体练习题的详细解答和批注说明。
This commit is contained in:
parent
a7aa274be3
commit
5cad182723
|
|
@ -1,3 +1,38 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
// 定义一个 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) {
|
||||
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]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ fn main() {
|
|||
println!("{}", user1.username);
|
||||
}
|
||||
```
|
||||
> 答: 可以通过编译,结构体变量类型都正确,使用方式正确
|
||||
|
||||
### 题目 1-2
|
||||
|
||||
|
|
@ -46,6 +47,7 @@ fn main() {
|
|||
println!("x = {}, y = {}", p.0, p.1);
|
||||
}
|
||||
```
|
||||
> 答: 可以通过编译,结构体变量类型都正确,使用方式正确
|
||||
|
||||
### 题目 1-3
|
||||
|
||||
|
|
@ -66,6 +68,7 @@ fn main() {
|
|||
println!("{}", user1.email);
|
||||
}
|
||||
```
|
||||
> 答: 可以通过编译,定义了一个可变结构体,可变结构体变量可以修改
|
||||
|
||||
### 题目 1-4
|
||||
|
||||
|
|
@ -85,6 +88,7 @@ fn main() {
|
|||
user1.email = String::from("new@example.com"); // user1 是不可变的
|
||||
}
|
||||
```
|
||||
> 答: 不可以通过编译,定义的`user1`是不可变的,不能修改
|
||||
|
||||
### 题目 1-5
|
||||
|
||||
|
|
@ -111,6 +115,7 @@ fn main() {
|
|||
println!("user2: {}", user2.username);
|
||||
}
|
||||
```
|
||||
> **[批注] 回答正确但原因有误。** "user1 是不可变的"与所有权转移无关——即使 `user1` 是 `mut`,`..user1` 同样会移动非 Copy 字段。真正原因:结构体更新语法 `..user1` 会将 `user1` 中未显式赋值的非 Copy 字段(`username`)移动到 `user2`,导致 `user1` 整体无法再使用。
|
||||
|
||||
### 题目 1-6
|
||||
|
||||
|
|
@ -137,6 +142,7 @@ fn main() {
|
|||
println!("user2 email: {}", user2.email);
|
||||
}
|
||||
```
|
||||
> 答: 可以通过编译,没有再次使用`user1.username`
|
||||
|
||||
### 题目 1-7
|
||||
|
||||
|
|
@ -155,6 +161,7 @@ fn main() {
|
|||
println!("{:?}", rect);
|
||||
}
|
||||
```
|
||||
> 答: 可以通过编译,使用`#[derive(Debug)]`宏,打印结构体变量
|
||||
|
||||
### 题目 1-8
|
||||
|
||||
|
|
@ -167,6 +174,7 @@ fn main() {
|
|||
println!("black R: {}, white R: {}", black.0, white.0);
|
||||
}
|
||||
```
|
||||
> 答: 可以通过编译,定义和使用方式都正确
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -190,6 +198,26 @@ fn main() {
|
|||
// 期望输出:《深入浅出 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:元组结构体
|
||||
|
||||
|
|
@ -206,6 +234,18 @@ fn main() {
|
|||
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:结构体更新语法
|
||||
|
||||
|
|
@ -233,6 +273,32 @@ fn main() {
|
|||
// 注意: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:定义方法
|
||||
|
||||
|
|
@ -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() {
|
||||
let rect1 = Rectangle { width: 30, height: 50 };
|
||||
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() {
|
||||
let square = Rectangle::square(10);
|
||||
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() {
|
||||
let mut counter = Counter::new();
|
||||
counter.increment();
|
||||
|
|
@ -353,6 +508,25 @@ fn main() {
|
|||
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
|
||||
|
||||
|
|
@ -368,6 +542,19 @@ fn main() {
|
|||
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
|
||||
|
||||
|
|
@ -389,6 +576,25 @@ fn main() {
|
|||
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
|
||||
|
||||
|
|
@ -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() {
|
||||
let user = User {
|
||||
name: String::from("小明"),
|
||||
|
|
@ -437,6 +665,30 @@ fn main() {
|
|||
c.set_value(20);
|
||||
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
|
||||
}
|
||||
```
|
||||
```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:几何图形
|
||||
|
||||
定义一个 `Circle` 结构体和 `Rectangle` 结构体,为它们分别实现 `area` 和 `perimeter` 方法。
|
||||
|
|
@ -520,6 +823,61 @@ fn main() {
|
|||
println!("矩形面积: {:.2}, 矩形周长: {:.2}", rect.area(), rect.perimeter());
|
||||
// 期望:矩形面积: 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:温度转换器
|
||||
|
|
@ -563,6 +921,52 @@ fn main() {
|
|||
println!("{}°F = {}°C", temp_f2.0, temp_c2.0);
|
||||
// 期望: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:链表节点
|
||||
|
|
@ -601,6 +1005,58 @@ fn main() {
|
|||
// 期望:链表元素: [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:购物车
|
||||
|
||||
|
|
@ -678,6 +1134,88 @@ fn main() {
|
|||
|
||||
// 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.email);
|
||||
> // println!("{}", user1.active);
|
||||
> 可以取消注释,使用结构体更新语法后,user1的username失效,email和active有效
|
||||
|
||||
### 题目 5-2
|
||||
|
||||
|
|
@ -738,12 +1280,18 @@ struct UserC {
|
|||
cached_display: Option<String>, // 缓存
|
||||
}
|
||||
```
|
||||
> **[批注] 原答太简略,只描述了"是什么"没回答"什么时候用"。**
|
||||
> - **设计 A(全部 String)**:结构体拥有数据,适合需要独立生命周期、长期持有数据的场景(如从函数返回、存入集合)。额外 heap 分配开销。
|
||||
> - **设计 B(全部 `&'a str`)**:仅仅借用外部数据,zero-copy,但受限于引用的生命周期 `'a`,结构体不能比它借用的数据活得更久。适合临时视图、解析器的 AST 节点等。
|
||||
> - **设计 C(混合 + 缓存)**:String 拥有核心数据,`cached_display` 作为惰性计算的缓存。适合需要性能优化但保留所有权的场景。
|
||||
|
||||
### 题目 5-3
|
||||
|
||||
分析以下代码,回答:
|
||||
1. `self`、`&self`、`&mut self` 三者在调用时的区别是什么?
|
||||
> 答:self:方法接收一个结构体的所有权,方法调用结束后,结构体将不再可用;&self:方法接收结构体的引用,方法调用结束后,结构体仍然可用;&mut self:方法接收结构体的可变引用,方法调用结束后,结构体仍然可用,并且允许修改结构体的字段。
|
||||
2. 当调用完 `into_value()` 之后,`counter` 是否还能使用?为什么?
|
||||
> **[批注] 基本正确,但表述可更精确:** `into_value()` 的参数是 `self`(不是引用),调用时 `counter` 的所有权被**移入**方法,方法结束 `self` 被 drop,返回的 `u32` 是 Copy 类型独立于原结构体。"返回所有权"的说法容易混淆——方法不是返回所有权,而是**接收**所有权。
|
||||
|
||||
```rust
|
||||
struct Counter {
|
||||
|
|
@ -781,7 +1329,7 @@ fn main() {
|
|||
### 题目 5-4
|
||||
|
||||
下面的代码涉及 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
|
||||
struct Circle {
|
||||
radius: f64,
|
||||
|
|
@ -816,6 +1364,13 @@ fn main() {
|
|||
### 题目 5-5
|
||||
|
||||
元组结构体 `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-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,允许使用 `{:?}` 格式化打印。
|
||||
|
||||
|
|
@ -1102,11 +1659,11 @@ impl ShoppingCart {
|
|||
### 五、综合思考题
|
||||
|
||||
**5-1**:
|
||||
- `user1.username`(String)— 已被移动给 user2,不可用
|
||||
- `user1.email`(String)— 被显式赋予了新值,没有被移动,**可用**
|
||||
- `user1.username`(String)— 已被 `..user1` 移动到 `user2`,**不可用**
|
||||
- `user1.email`(String)— 在 `user2` 中被显式赋予新值,**未被移动,可用**
|
||||
- `user1.active`(bool,Copy 类型)— 被复制,**可用**
|
||||
|
||||
关键点:结构体更新语法 `..user1` 相当于 `username: user1.username`、`active: user1.active` 等。对于 String 类型是移动,对于 bool 是复制。显式赋值的字段不会从 user1 移动。
|
||||
> **[批注] 此答案修正了原隐藏答案关于 user1.email 的错误。** 显式覆盖的字段不会从原结构体移动。
|
||||
|
||||
**5-2**:
|
||||
- **设计 A**:适合需要拥有数据的场景,如从函数返回新结构体、需要独立生命周期、长期持有的数据
|
||||
|
|
|
|||
Loading…
Reference in New Issue