简介
在很小的示例中,分别使用多个变量即可;但在实际程序中,通常需要将相关数据保存在同一个值中。Rust 的 struct 用于定义这种记录的结构,impl 代码块则为记录提供属于它的操作。
你将通过四处小修改完成预先准备好的 InventoryItem 模型:定义字段、构造有效的库存项、通过 &self 计算库存价值,以及通过 &mut self 更新数量。最终程序将验证保存的状态和方法的行为。
定义库存记录
在此步骤中,你将定义一个库存项所包含的三项数据。
进入预先准备好的 Cargo 项目,并打开源文件:
cd /home/labex/project/inventory-item
nano src/main.rs
声明 struct InventoryItem { ... } 会引入一种新的记录类型。在花括号内,每个字段都由名称、冒号和类型组成。每个 InventoryItem 值都必须提供这些字段。
将步骤 1 的注释替换为下面三行字段定义:
name: String,
price_cents: u32,
quantity: u32,
name 用于保存文本,两个 u32 字段用于保存非负整数。行末的逗号用于分隔字段,也便于之后添加或调整字段顺序。
按 Ctrl+O 保存,按 Enter 确认,然后按 Ctrl+X 退出。让 Cargo 检查类型定义:
cargo check
如果看到没有警告的 Finished 结果,说明结构体的形状有效,并且每个预先准备好的值都有明确用途。构造函数中仍然包含 todo!,这是表示代码尚未完成的临时标记。Rust 允许它通过 cargo check,但如果运行执行到 todo! 的代码路径,程序会因 panic 而停止。你将在下一步运行程序前替换它。
构造完整的库存项
在此步骤中,你将把 new 关联函数改造成一个返回完整 InventoryItem 的构造函数。
impl InventoryItem 代码块用于将操作与该类型组织在一起。new 是一个关联函数,因为它不接收 self;你可以通过类型调用它:InventoryItem::new(...)。而像 value_cents 这样的方法会接收 self,通过值调用时写作 item.value_cents()。返回类型 Self 在此 impl 代码块中是 InventoryItem 的另一种写法。
打开源文件:
nano src/main.rs
在 new 内,将整行 todo!(...) 替换为:
Self { name, price_cents, quantity }
这是一个结构体表达式。Rust 支持字段简写:当参数名与字段名相同时,name 等同于 name: name。该表达式没有分号,因为它就是函数返回的值。
保存并退出,然后检查并运行程序:
cargo check
cargo run --quiet
此时应看到以下输出:
Preparing Notebook at 250 cents with 4 units
Item: Notebook
Unit price: 250 cents
Starting value: 0 cents
Adding 3 units
Quantity after restock: 4
Final value: 0 cents
现在,库存项已经使用提供的字段值创建完成。输出中的两个 0 和数量未发生变化,是因为另外两个方法仍然是占位实现,因此此时出现这些结果是正常的。
使用 &self 计算价值
在此步骤中,你将完成一个读取两个字段的方法。该方法不会取得库存项的所有权,也不会修改库存项。
参数 &self 是对当前 InventoryItem 的共享引用。它是借用值的简写形式,其具体类型为 &InventoryItem。调用 item.value_cents() 时,方法会自动接收该参数。
打开源文件:
nano src/main.rs
在 value_cents 内,只将占位符 0 替换为:
self.price_cents * self.quantity
点号用于从借用的库存项中选择字段。乘法会得到以分为单位的总价值;由于表达式末尾没有分号,它会成为该方法返回的 u32 值。
保存并退出,然后运行程序:
cargo run --quiet
此时,表示价值的两行应变为:
Starting value: 1000 cents
...
Final value: 1000 cents
4 个单位、每个 250 分,总价值就是 1000 分。两行的结果仍然相同,因为 restock 还没有修改数量;最后一步将完成这次受控修改。
使用 &mut self 补货
在此步骤中,你将完成一个通过独占借用访问来修改字段的方法。
接收者 &mut self 是对当前库存项的可变引用。它允许方法更新字段,而不取得库存项的所有权。main 中的绑定已经声明为 let mut item,因此可以提供这次临时的可变访问。
打开源文件:
nano src/main.rs
将 restock 内步骤 4 的注释替换为:
self.quantity += amount;
+= 运算符会将右侧的值加到现有字段上,并把结果写回该字段。这是一条语句,因此末尾需要加分号。
保存并退出,然后检查并运行完成后的模型:
cargo check
cargo run --quiet
完整输出应为:
Preparing Notebook at 250 cents with 4 units
Item: Notebook
Unit price: 250 cents
Starting value: 1000 cents
Adding 3 units
Quantity after restock: 7
Final value: 1750 cents
数量从 4 变为 7,同一个 value_cents 方法也读取到了更新后的状态。restock 执行完毕后,可变借用结束,因此后续代码可以正常读取该库存项。
总结
你定义了一个用于集中保存相关字段的结构体,通过 Self 构造函数创建了值,使用 &self 方法读取状态,并使用 &mut self 方法更新状态。最终的库存输出证明了构造、计算和修改可以协同工作。


