属性系统 (Property System)
概述
Valkyrie 的属性系统提供了一种优雅的方式来封装字段访问,允许开发者定义 getter 和 setter 方法,同时保持简洁的访问语法。属性系统遵循统一访问原则,使得字段访问和方法调用在语法上保持一致。
基本属性定义
Getter 属性
valkyrie
class Rectangle {
width: f64,
height: f64,
# 计算属性 - 面积
get area(self) -> f64 {
self.width * self.height
}
# 计算属性 - 周长
get perimeter(self) -> f64 {
2.0 * (self.width + self.height)
}
}
# 使用方式
let rect = new Rectangle { width: 10.0, height: 5.0 }
let area = rect.area # 调用 getter,返回 50.0
let perimeter = rect.perimeter # 调用 getter,返回 30.0Setter 属性
valkyrie
class Temperature {
celsius: f64,
# Getter - 获取华氏温度
get fahrenheit(self) -> f64 {
self.celsius * 9.0 / 5.0 + 32.0
}
# Setter - 设置华氏温度
set fahrenheit(mut self, value: f64) {
self.celsius = (value - 32.0) * 5.0 / 9.0
}
# Getter - 获取开尔文温度
get kelvin(self) -> f64 {
self.celsius + 273.15
}
# Setter - 设置开尔文温度
set kelvin(mut self, value: f64) {
self.celsius = value - 273.15
}
}
# 使用方式
let mut temp = new Temperature { celsius: 25.0 }
print("摄氏度: ${temp.celsius}") # 25.0
print("华氏度: ${temp.fahrenheit}") # 77.0
print("开尔文: ${temp.kelvin}") # 298.15
# 通过 setter 修改温度
temp.fahrenheit = 86.0 # 设置华氏温度
print("摄氏度: ${temp.celsius}") # 30.0
temp.kelvin = 300.0 # 设置开尔文温度
print("摄氏度: ${temp.celsius}") # 26.85只读和只写属性
只读属性
valkyrie
class Person {
first_name: String,
last_name: String,
birth_year: u32,
# 只读属性 - 全名
get full_name(self) -> String {
"${self.first_name} ${self.last_name}"
}
# 只读属性 - 年龄(基于当前年份)
get age(self) -> u32 {
2024 - self.birth_year # 简化示例
}
}
let person = Person {
first_name: "张",
last_name: "三",
birth_year: 1990
}
print(person.full_name) # "张 三"
print(person.age) # 34
# person.full_name = "李四" # 编译错误:没有 setter只写属性
valkyrie
class Logger {
messages: Vector<String>,
# 只写属性 - 添加日志消息
set message(mut self, msg: String) {
let timestamp = get_current_timestamp()
self.messages.push("[${timestamp}] ${msg}")
}
# 获取所有消息的方法
get_messages(self) -> &Vector<String> {
&self.messages
}
}
let mut logger = new Logger { messages: Vec::new() }
logger.message = "系统启动" # 使用 setter
logger.message = "用户登录" # 使用 setter
# let msg = logger.message # 编译错误:没有 getter属性验证
valkyrie
class BankAccount {
balance: f64,
min_balance: f64,
# 带验证的 setter
set balance(mut self, value: f64) {
if value < self.min_balance {
panic("余额不能低于最低限额: ${self.min_balance}")
}
self.balance = value
}
get balance(self) -> f64 {
self.balance
}
}
let mut account = BankAccount {
balance: 1000.0,
min_balance: 100.0
}
account.balance = 500.0 # 正常设置
# account.balance = 50.0 # 运行时 panic懒加载属性
valkyrie
class DataProcessor {
raw_data: Vector<String>,
processed_data: Option<Vector<ProcessedItem>>,
# 懒加载的计算属性
get processed(mut self) -> &Vector<ProcessedItem> {
if self.processed_data.is_none() {
let processed = self.raw_data
.iter()
.map({ |item| self.process_item(item) })
.collect()
self.processed_data = Some(processed)
}
if let Some(ref data) = self.processed_data {
data
} else {
@unreachable()
}
}
process_item(self, item: &String) -> ProcessedItem {
# 复杂的处理逻辑
ProcessedItem::from(item)
}
}属性链式调用
valkyrie
class Builder {
name: Option<String>,
age: Option<u32>,
email: Option<String>,
# 链式 setter
set name(mut self, value: String) -> Self {
self.name = Some(value)
self
}
set age(mut self, value: u32) -> Self {
self.age = Some(value)
self
}
set email(mut self, value: String) -> Self {
self.email = Some(value)
self
}
build(self) -> Person {
Person {
name: self.name.unwrap_or("Unknown"),
age: self.age.unwrap_or(0),
email: self.email.unwrap_or("unknown@example.com")
}
}
}
# 链式调用
let person = Builder::new()
.name("Alice")
.age(30)
.email("alice@example.com")
.build()静态属性
valkyrie
class MathConstants {
# 静态只读属性
static get pi() -> f64 {
3.14159265359
}
static get e() -> f64 {
2.71828182846
}
# 静态可变属性
static mut counter: u32 = 0
static get next_id() -> u32 {
Self::counter += 1
Self::counter
}
}
# 使用静态属性
let pi_value = MathConstants::pi
let id1 = MathConstants::next_id # 1
let id2 = MathConstants::next_id # 2属性重写
valkyrie
class Shape {
# 虚拟属性
virtual get area(self) -> f64 {
0.0
}
}
class Circle: Shape {
radius: f64,
# 重写父类属性
override get area(self) -> f64 {
3.14159 * self.radius * self.radius
}
}
class Square: Shape {
side: f64,
# 重写父类属性
override get area(self) -> f64 {
self.side * self.side
}
}最佳实践
1. 使用属性进行数据封装
valkyrie
# 好的实践:使用属性封装内部状态
class Counter {
value: u32,
get count(self) -> u32 {
self.value
}
set count(mut self, new_value: u32) {
if new_value > 1000 {
panic("计数器值不能超过 1000")
}
self.value = new_value
}
increment(mut self) {
self.count = self.count + 1
}
}2. 避免副作用过大的 Getter
valkyrie
# 避免:getter 中有复杂的副作用
class BadExample {
get data(mut self) -> Vector<String> {
# 不好:每次访问都重新计算
expensive_computation()
}
}
# 推荐:使用懒加载或缓存
class GoodExample {
cached_data: Option<Vector<String>>,
get data(mut self) -> &Vector<String> {
if self.cached_data.is_none() {
self.cached_data = Some(expensive_computation())
}
self.cached_data.as_ref().unwrap()
}
}3. 保持属性语义的一致性
valkyrie
class Rectangle {
width: f64,
height: f64,
# 好的实践:getter 和 setter 操作相同的概念
get area(self) -> f64 {
self.width * self.height
}
# 如果提供 area setter,应该合理地更新 width 和 height
set area(mut self, new_area: f64) {
let ratio = (new_area / self.area()).sqrt()
self.width *= ratio
self.height *= ratio
}
}总结
Valkyrie 的属性系统提供了:
- 统一访问原则:字段和计算属性使用相同的访问语法
- 数据封装:通过 getter/setter 控制数据访问
- 计算属性:支持动态计算的属性值
- 验证机制:在 setter 中添加数据验证逻辑
- 懒加载:支持延迟计算和缓存
- 链式调用:支持流畅的 API 设计
正确使用属性系统可以提高代码的封装性、可维护性和用户体验。