learning-rust/part4/struct练习题.md

1130 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Rust 结构体Struct练习题
> 建议先手动写出每道题的答案,再运行代码验证。
## 目录
- [一、基础题:判断正误](#一基础题判断正误)
- [二、填空题:补充代码](#二填空题补充代码)
- [三、找出并修复错误](#三找出并修复错误)
- [四、编程题](#四编程题)
- [五、综合思考题](#五综合思考题)
- [参考答案](#参考答案)
---
## 一、基础题:判断正误
判断以下代码能否通过编译。如果可以,说明原因;如果不能,指出错误原因。
### 题目 1-1
```rust
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
};
println!("{}", user1.username);
}
```
### 题目 1-2
```rust
struct Point(f64, f64);
fn main() {
let p = Point(3.0, 4.0);
println!("x = {}, y = {}", p.0, p.1);
}
```
### 题目 1-3
```rust
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let mut user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
};
user1.email = String::from("new_email@example.com");
println!("{}", user1.email);
}
```
### 题目 1-4
```rust
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
};
user1.email = String::from("new@example.com"); // user1 是不可变的
}
```
### 题目 1-5
```rust
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
};
let user2 = User {
email: String::from("bob@example.com"),
..user1
};
println!("user1: {}", user1.username);
println!("user2: {}", user2.username);
}
```
### 题目 1-6
```rust
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
};
let user2 = User {
email: String::from("bob@example.com"),
..user1
};
println!("user1 email: {}", user1.email);
println!("user2 email: {}", user2.email);
}
```
### 题目 1-7
```rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect = Rectangle {
width: 30,
height: 50,
};
println!("{:?}", rect);
}
```
### 题目 1-8
```rust
struct Color(i32, i32, i32);
fn main() {
let black = Color(0, 0, 0);
let white = Color(255, 255, 255);
println!("black R: {}, white R: {}", black.0, white.0);
}
```
---
## 二、填空题:补充代码
补全下列代码使其能通过编译并达到期望输出。
### 题目 2-1定义结构体并实例化
```rust
// 填空:定义一个名为 Book 的结构体,包含 title(String)、author(String)、pages(u32)
fn main() {
let book = ________ {
title: String::from("深入浅出 Rust"),
________: String::from("张三"),
pages: 320,
};
println!("《{}》作者:{},共 {} 页", book.title, book.author, book.pages);
// 期望输出:《深入浅出 Rust》作者张三共 320 页
}
```
### 题目 2-2元组结构体
```rust
// 填空:定义一个元组结构体 RGB包含三个 u8 值(红、绿、蓝)
struct RGB(________, ________, ________);
fn main() {
let red = RGB(255, 0, 0);
let green = RGB(0, 255, 0);
println!("红色: ({}, {}, {})", red.0, red.1, ________);
println!("绿色: ({}, {}, {})", green.0, green.1, green.2);
}
```
### 题目 2-3结构体更新语法
```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 复制
};
println!("s1: {:?}, s2: {:?}", s1, s2);
// 注意s1.score 和 s1.age 在更新后是否还能使用?为什么?
}
```
### 题目 2-4定义方法
```rust
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 填空:定义一个 area 方法,计算矩形的面积
fn ________(&self) -> ________ {
self.width ________ self.height
}
// 填空:定义一个 can_hold 方法,判断当前矩形能否容纳另一个矩形
fn can_hold(&self, other: ________) -> 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 };
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
}
```
### 题目 2-5关联函数
```rust
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 填空:定义一个关联函数 square接收一个边长参数返回一个正方形 Rectangle
fn ________(size: u32) -> ________ {
Rectangle {
width: size,
height: ________,
}
}
}
fn main() {
let square = Rectangle::square(10);
println!("正方形: {} x {}", square.width, square.height);
// 期望输出:正方形: 10 x 10
}
```
### 题目 2-6self / &self / &mut self
```rust
struct Counter {
count: u32,
}
impl Counter {
// A创建新的 Counter初始值为 0
fn new() -> Counter {
Counter { count: 0 }
}
// B只读取计数值 —— 参数应该是什么?
fn value(________) -> u32 {
self.count
}
// C计数 +1 —— 参数应该是什么?
fn increment(________) {
self.count += 1;
}
// D消费 Counter返回最终值 —— 参数应该是什么?
fn into_value(________) -> u32 {
self.count
}
}
fn main() {
let mut counter = Counter::new();
counter.increment();
counter.increment();
println!("当前值: {}", counter.value()); // 期望输出2
println!("最终值: {}", counter.into_value()); // 期望输出2
// println!("{}", counter.value()); // 如果取消注释会怎样?
}
```
---
## 三、找出并修复错误
以下每段代码都有编译错误,请指出错误并写出修正后的代码。
### 题目 3-1
```rust
struct User {
username: &str,
email: &str,
active: bool,
}
fn main() {
let user = User {
username: "alice",
email: "alice@example.com",
active: true,
};
println!("{}", user.username);
}
```
### 题目 3-2
```rust
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("{}", p); // 想要打印 p
}
```
### 题目 3-3
```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
```rust
struct User {
name: String,
age: u32,
}
impl User {
fn greet(self) {
println!("你好,我是 {},今年 {} 岁", self.name, self.age);
}
}
fn main() {
let user = User {
name: String::from("小明"),
age: 18,
};
user.greet();
user.greet(); // 第二次调用
}
```
### 题目 3-5
```rust
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();
c.set_value(20);
println!("v = {}", v);
}
```
---
## 四、编程题
### 题目 4-1学生管理系统基础结构
定义一个 `Student` 结构体,包含 `name`String、`id`u32、`grades`Vec\<u32\>),并实现以下方法:
```rust
struct Student {
name: String,
id: u32,
grades: Vec<u32>,
}
impl Student {
// 1. 关联函数 new创建一个新学生成绩列表为空
fn new(name: String, id: u32) -> Student {
// 你的代码
}
// 2. 添加一门成绩
fn add_grade(&mut self, grade: u32) {
// 你的代码
}
// 3. 计算平均成绩,如果没有成绩则返回 0.0
fn average_grade(&self) -> f64 {
// 你的代码
}
// 4. 判断是否及格(平均分 >= 60
fn is_passing(&self) -> bool {
// 你的代码
}
}
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 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` 方法。
```rust
use std::f64::consts::PI;
struct Circle {
radius: f64,
}
struct Rectangle {
width: f64,
height: f64,
}
// 你的代码:为 Circle 实现 area 和 perimeter
// 你的代码:为 Rectangle 实现 area 和 perimeter
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温度转换器
使用元组结构体实现温度类型,使不同类型的温度之间不会混淆。
```rust
// 定义三个元组结构体Celsius(f64)、Fahrenheit(f64)、Kelvin(f64)
// 你的代码
impl Celsius {
// 转换为华氏度
fn to_fahrenheit(&self) -> Fahrenheit {
// °F = °C × 9/5 + 32
}
// 转换为开尔文
fn to_kelvin(&self) -> Kelvin {
// K = °C + 273.15
}
}
impl Fahrenheit {
// 转换为摄氏度
fn to_celsius(&self) -> Celsius {
// °C = (°F - 32) × 5/9
}
}
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链表节点
使用结构体实现一个单向链表的节点,要求展示你对 `Box` 和所有权机制的理解。
```rust
// 定义一个 ListNode 结构体,包含 value(i32) 和 next(Option<Box<ListNode>>)
// 你的代码
impl ListNode {
// 创建一个新节点
fn new(value: i32) -> ListNode {
// 你的代码
}
// 在链表末尾追加一个节点(递归实现)
fn append(&mut self, value: i32) {
// 你的代码
}
// 将所有节点的值收集到一个 Vec 中
fn collect(&self) -> Vec<i32> {
// 你的代码
}
}
fn main() {
let mut head = ListNode::new(1);
head.append(2);
head.append(3);
let values = head.collect();
println!("链表元素: {:?}", values);
// 期望:链表元素: [1, 2, 3]
}
```
### 题目 4-5购物车
定义一个 `ShoppingCart` 结构体包含商品列表Vec设计合理的所有权和借用关系。
```rust
#[derive(Debug, Clone)]
struct Item {
name: String,
price: f64,
quantity: u32,
}
impl Item {
fn new(name: &str, price: f64, quantity: u32) -> Item {
// 你的代码
}
// 计算该商品总价(单价 × 数量)
fn total(&self) -> f64 {
// 你的代码
}
}
struct ShoppingCart {
items: Vec<Item>,
}
impl ShoppingCart {
// 创建空购物车
fn new() -> ShoppingCart {
// 你的代码
}
// 添加商品
fn add_item(&mut self, item: Item) {
// 你的代码
}
// 计算购物车中所有商品的总价
fn total(&self) -> f64 {
// 你的代码
}
// 获取商品种类数量
fn item_count(&self) -> usize {
// 你的代码
}
// 打印购物车明细(消耗购物车所有权)
fn print_receipt(self) {
// 你的代码:遍历所有商品,打印名称、单价、数量、小计
// 最后打印总价
}
}
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();
// 期望输出:
// === 购物明细 ===
// 键盘 × 1 @ 299.00 = 299.00
// 鼠标 × 2 @ 159.00 = 318.00
// 显示器 × 1 @ 1899.00 = 1899.00
// ----------------------
// 总计: 2516.00
// ======================
// println!("{:?}", cart.item_count()); // 如果取消注释会怎样?为什么?
}
```
---
## 五、综合思考题
### 题目 5-1
以下代码为什么能通过编译?`user1` 的 `active` 字段是 `bool` 类型(实现 Copy`username``email``String` 类型(未实现 Copy使用结构体更新语法后各自的可用性如何
```rust
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
};
let user2 = User {
email: String::from("bob@example.com"),
..user1
};
// 下面哪些行可以取消注释?为什么?
// println!("{}", user1.username);
// println!("{}", user1.email);
// println!("{}", user1.active);
}
```
### 题目 5-2
对比以下三种设计。在什么场景下分别应该使用哪种?
```rust
// 设计 A所有字段都是 String自有类型
struct UserA {
name: String,
email: String,
}
// 设计 B所有字段都是 &str借用
struct UserB<'a> {
name: &'a str,
email: &'a str,
}
// 设计 C混合
struct UserC {
name: String,
email: String,
cached_display: Option<String>, // 缓存
}
```
### 题目 5-3
分析以下代码,回答:
1. `self`、`&self`、`&mut self` 三者在调用时的区别是什么?
2. 当调用完 `into_value()` 之后,`counter` 是否还能使用?为什么?
```rust
struct Counter {
count: u32,
}
impl Counter {
fn value(&self) -> u32 {
self.count
}
fn increment(&mut self) {
self.count += 1;
}
fn reset(&mut self) {
self.count = 0;
}
fn into_value(self) -> u32 {
self.count
}
}
fn main() {
let mut counter = Counter { count: 0 };
counter.increment();
counter.increment();
println!("value: {}", counter.value());
let n = counter.into_value();
println!("final: {}", n);
}
```
### 题目 5-4
下面的代码涉及 struct、impl 和模块的组合。有两个 struct 都定义了 `area` 方法Rust 通过什么机制区分它们?
```rust
struct Circle {
radius: f64,
}
struct Rectangle {
width: f64,
height: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {
let c = Circle { radius: 3.0 };
let r = Rectangle { width: 4.0, height: 5.0 };
println!("圆面积: {:.2}", c.area()); // Circle::area(&c)
println!("矩形面积: {:.2}", r.area()); // Rectangle::area(&r)
}
```
### 题目 5-5
元组结构体 `struct Point(i32, i32)` 和普通元组 `(i32, i32)` 有什么区别?在什么场景下应该使用元组结构体而不是普通元组?
---
## 参考答案
> 请独立完成再查看答案。
<details>
<summary>点击展开答案</summary>
### 一、基础题
**1-1**:✅ 通过编译。结构体中的字段顺序不要求与定义一致,使用命名即可。
**1-2**:✅ 通过编译。元组结构体使用 `.索引` 方式访问字段。
**1-3**:✅ 通过编译。`mut` 修饰的结构体实例,其所有字段都是可变的。
**1-4**:❌ 编译错误。`user1` 不是 `mut`不能修改其字段。Rust 中可变性是整个结构体级别的,不能只标记某个字段为 `mut`
**1-5**:❌ 编译错误。结构体更新语法 `..user1` 会移动 `user1` 中未实现 Copy 的字段(`username` 和 `email`)。`user1.username` 已被移动到 `user2``user1` 不再可用。
**1-6**:❌ 编译错误。同上,`..user1` 移动了 `user1``username` 字段,而 `email` 字段被显式赋值所以没有移动。但 `user1` 作为一个整体已部分移动,不能再访问 `user1.email`
**1-7**:✅ 通过编译。`#[derive(Debug)]` 自动为结构体实现了 `Debug` trait允许使用 `{:?}` 格式化打印。
**1-8**:✅ 通过编译。元组结构体的实例各自独立,互不影响。
### 二、填空题
**2-1**
```rust
struct Book {
title: String,
author: String,
pages: u32,
}
let book = Book {
title: String::from("深入浅出 Rust"),
author: String::from("张三"),
pages: 320,
};
```
**2-2**
```rust
struct RGB(u8, u8, u8);
println!("红色: ({}, {}, {})", red.0, red.1, red.2);
```
**2-3**
```rust
let s2 = Student {
name: String::from("小红"),
..s1
};
// s1.score 和 s1.age 在更新后是否还能使用?
// — 如果字段类型是 Copy 的u32可以继续使用
// — 如果字段类型不是 Copy 的String已被移动不能使用
// 这里 age 和 score 都是 u32Copy所以 s1.score 和 s1.age 仍然可用
```
**2-4**
```rust
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
```
**2-5**
```rust
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
```
**2-6**
```rust
fn value(&self) -> u32 { self.count } // 不可变借用
fn increment(&mut self) { self.count += 1; } // 可变借用
fn into_value(self) -> u32 { self.count } // 获取所有权
// 最后一行取消注释会报错into_value() 消费了 counter之后不能再使用
```
### 三、修复错误
**3-1**:结构体使用了引用字段但没有标注生命周期。修复:
```rust
struct User<'a> {
username: &'a str,
email: &'a str,
active: bool,
}
```
或者改用 `String` 类型(推荐给初学者):
```rust
struct User {
username: String,
email: String,
active: bool,
}
```
**3-2**`println!("{}", p)` 需要 `Display` trait但只 derive 了 `Debug`。修复:
```rust
println!("{:?}", p); // 使用 Debug 格式化
// 或 println!("{}", p) 行不通 → 需改为 println!("{:?}", p)
```
**3-3**:方法调用语法错误。`rect::area()` 应改为 `rect.area()`。`::` 用于关联函数,`.` 用于方法调用。
**3-4**`greet(self)` 获取了所有权,第一次调用后 `user` 被消费。修复:
```rust
fn greet(&self) { // 改为不可变引用
println!("你好,我是 {},今年 {} 岁", self.name, self.age);
}
```
**3-5**`get_value` 的不可变借用和 `set_value` 的可变借用存在生命周期重叠。修复:让 `v``c.set_value` 之前结束使用:
```rust
fn main() {
let mut c = Container { value: 10 };
let v = c.get_value();
println!("v = {}", v); // 先使用 v
c.set_value(20); // v 不再使用,可以创建可变借用
}
```
### 四、编程题
**4-1**
```rust
fn new(name: String, id: u32) -> Student {
Student { name, id, grades: Vec::new() }
}
fn add_grade(&mut self, grade: u32) {
self.grades.push(grade);
}
fn average_grade(&self) -> f64 {
if self.grades.is_empty() {
0.0
} else {
self.grades.iter().sum::<u32>() as f64 / self.grades.len() as f64
}
}
fn is_passing(&self) -> bool {
self.average_grade() >= 60.0
}
```
**4-2**
```rust
impl Circle {
fn area(&self) -> f64 {
PI * self.radius * self.radius
}
fn perimeter(&self) -> f64 {
2.0 * PI * self.radius
}
}
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
```
**4-3**
```rust
struct Celsius(f64);
struct Fahrenheit(f64);
struct Kelvin(f64);
impl Celsius {
fn to_fahrenheit(&self) -> Fahrenheit {
Fahrenheit(self.0 * 9.0 / 5.0 + 32.0)
}
fn to_kelvin(&self) -> Kelvin {
Kelvin(self.0 + 273.15)
}
}
impl Fahrenheit {
fn to_celsius(&self) -> Celsius {
Celsius((self.0 - 32.0) * 5.0 / 9.0)
}
}
```
**4-4**
```rust
struct ListNode {
value: i32,
next: Option<Box<ListNode>>,
}
impl ListNode {
fn new(value: i32) -> ListNode {
ListNode { value, next: None }
}
fn append(&mut self, value: i32) {
match &mut self.next {
Some(next_node) => next_node.append(value),
None => self.next = Some(Box::new(ListNode::new(value))),
}
}
fn collect(&self) -> Vec<i32> {
let mut result = vec![self.value];
let mut current = &self.next;
while let Some(node) = current {
result.push(node.value);
current = &node.next;
}
result
}
}
```
**4-5**
```rust
impl Item {
fn new(name: &str, price: f64, quantity: u32) -> Item {
Item { name: String::from(name), price, quantity }
}
fn total(&self) -> f64 {
self.price * self.quantity as f64
}
}
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()
}
fn item_count(&self) -> usize {
self.items.len()
}
fn print_receipt(self) {
println!("=== 购物明细 ===");
for item in &self.items {
println!("{} × {} @ {:.2} = {:.2}", item.name, item.quantity, item.price, item.total());
}
println!("----------------------");
println!("总计: {:.2}", self.total());
println!("======================");
}
}
// print_receipt(self) 消耗了购物车所有权,之后再调用 item_count() 会报错
```
### 五、综合思考题
**5-1**
- `user1.username`String— 已被移动给 user2不可用
- `user1.email`String— 被显式赋予了新值,没有被移动,**可用**
- `user1.active`boolCopy 类型)— 被复制,**可用**
关键点:结构体更新语法 `..user1` 相当于 `username: user1.username`、`active: user1.active` 等。对于 String 类型是移动,对于 bool 是复制。显式赋值的字段不会从 user1 移动。
**5-2**
- **设计 A**:适合需要拥有数据的场景,如从函数返回新结构体、需要独立生命周期、长期持有的数据
- **设计 B**:适合临时借用、只读引用外部数据、需要避免堆分配的场景;缺点是结构体受限于引用的生命周期
- **设计 C**:适合需要高性能 + 灵活性的场景,但增加了维护缓存的复杂性
**5-3**
- `&self`:不可变借用,只读,可多次调用,调用后实例仍可用
- `&mut self`:可变借用,可修改,同时只能有一个,调用后实例仍可用
- `self`:获取所有权,可修改或消费,调用后实例被 drop不可再用
- `into_value()` 获取了 `counter` 的所有权,调用后 `counter` 不再可用
**5-4**Rust 通过**方法调用的接收者类型**来区分。`c.area()` 的接收者是 `Circle`,调用 `Circle::area``r.area()` 的接收者是 `Rectangle`,调用 `Rectangle::area`
**5-5**
- 元组结构体 `Point(i32, i32)` 是一个**命名类型**,与 `Vec2(i32, i32)` 是不同的类型,不能互相赋值,提供了类型安全
- 普通元组 `(i32, i32)` 是匿名类型,任何 `(i32, i32)` 都可以互相赋值
- 使用元组结构体的场景:需要类型安全地区分语义不同的同构数据(如 `Celsius(f64)` vs `Fahrenheit(f64)`),或为特定类型实现方法和 trait
</details>