私有字段
本课属于 Coddy Rust 学习旅程的“面向对象编程”单元。第 10 课,共 61 课。
在上一课中,你把所有内容都设为公开:结构体、它的字段和方法。但真正的封装意味着控制数据的访问方式。在 Rust 中,你可以让结构体公开,同时将它的字段设为私有。
考虑一个 Wallet,它的余额永远不应为负数。如果字段是公开的,任何人都可以将它设为任意值:
// wallet.rs
pub struct Wallet {
balance: f64, // 没有 pub 就是私有的!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
注意,Wallet 是公开的,但 balance 没有 pub 关键字。这意味着模块外的代码可以使用构造函数创建 Wallet,但不能直接读取或修改余额字段:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // 错误!字段是私有的
// w.balance = -50.0; // 错误!无法访问私有字段
}
这就是封装的基础:结构体控制自己的数据。外部代码必须通过你提供的方法来访问数据,这意味着你可以添加验证、日志记录或其他逻辑。这样可以保护数据,使其不会处于无效状态。
在接下来的课程中,你将学习如何通过 getter 和 setter 方法来受控地访问这些私有数据。
挑战
简单让我们构建一个温度传感器系统,通过将敏感数据保存在模块中来演示封装。
你将创建两个文件来组织代码:
sensor.rs:定义一个TemperatureSensor结构体,包含两个字段:location(String)和reading(f64)。结构体应设为公开,以便其他文件可以使用它,但两个字段都要保持私有:外部代码不能直接访问或修改传感器的数据。添加一个公开的new构造函数,接收位置名称和初始温度读数。main.rs:引入传感器模块,并使用构造函数创建一个TemperatureSensor。由于字段是私有的,你不能直接打印它们,而应打印一条确认消息,说明传感器已成功创建。
这个挑战侧重于私有字段这一核心概念:结构体可以访问,但其内部数据受到保护。外部代码只能通过你提供的方法与传感器交互(在本例中,只有构造函数)。
你的输出应严格遵循以下格式:
Sensor created for: {location}要访问位置并打印出来,你需要让 new 函数在返回传感器之前打印这条消息,因为字段本身是私有的。
例如,如果你创建一个位置为 "Kitchen"、读数为 22.5 的传感器,输出将是:
Sensor created for: Kitchen你将收到两个输入:位置名称和初始温度读数。
亲手试试
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// 读取输入
let mut location = String::new();
std::io::stdin().read_line(&mut location).expect("Failed to read line");
let location = location.trim().to_string();
let mut reading_str = String::new();
std::io::stdin().read_line(&mut reading_str).expect("Failed to read line");
let reading: f64 = reading_str.trim().parse().expect("Failed to parse reading");
// TODO: 用构造函数创建一个 TemperatureSensor
// new 函数会负责打印确认消息
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Rust 在线编译器