结构体
和元组一样,结构体中的数据可以拥有不同的类型。而和元组不一样的是,结构体需要给每个数据赋予名字以便清楚地表明它们的意义,可以理解为 JS 中的对象。
定义结构体
在创建结构体之前需要先声明结构体和成员的类型,可以理解为 TS 中的 Interface:
struct User {
name: String,
age: i32,
}
复制代码
创建结构体:
// 使用mut关键字来使结构体可变,意味着其中的所有数据都会可变
let mut user = User {
name: String::from("xiao_ming"),
age: 10,
};
// 取值
println!("{}", user.name); // "xiao_ming"
println!("{}", user.age); // 10
// 修改字段
user.age = 11
println!("{}", user.age); // 11
复制代码
使用工厂模式创建结构体:
fn user_factory(name: String) -> User {
User {
name, // 属性名和属性值相同时,可以简写
age: 10,
}
}
let mut user = user_factory(String::from("xiao_ming"));
println!("{}", user.name); // "xiao_ming"
println!("{}", user.age); // 10
复制代码
结构体更新语法,类似于 JS 中的对象合并运算符:
let user = User {
name: String::from("xiao_ming"),
age: 11,
}
let user2 = User {
age: 10,
..user // 注意这里的user只能放在其他字段的末尾
};
println!("{}", user2.name); // "xiao_ming"
println!("{}", user2.age); // 10
复制代码
上面 age 输出的是 user2 的 10,而不是 user 的 11,说明结构体更新语法只在 user 中提取 user2 中没有的内容,并不会全部使用 user 进行覆盖。
元组结构体
元组结构体同样是 struct 关键字来定义:
struct Color(u8, u8, u8);
struct Point(i32, i32, i32);
复制代码
定义结构体数据:
let black = Color(0, 0, 0);
let point = Point(100, 100, 100);
println!("r:{} g:{} b:{}", black.0, black.1, black.2); // r: 0 g: 0 b: 0
println!("x:{} y:{} z:{}", point.0, point.1, point.2); // x: 100 y: 100 z: 100
复制代码
空结构体
rust 允许创建没有任何字段的结构体,因为这种结构体与空元组()十分相似,所以也被称为空结构体:
计算长方形面积的案例:
定义一个 area 函数用于计算长方形面积,使用 width 和 height 两个参数表示长方形:
fn area(width: u32, height: u32) -> u32 {
width * height
}
println!("area: {}", area(100, 100)); // area: 10000
复制代码
使用元组结构体形式:
// 定义一个元组类型的结构体
struct Rect (u32, u32);
// 将函数参数改为接收一个Rect类型的参数
fn area(rect: &Rect) -> u32 {
rect.0 * rect.1
}
// 创建一个Rect
let rect = Rect(100, 100);
println!("area: {}", area(rect)); // area: 10000
复制代码
使用结构体形式:
// 定义一个普通结构体
struct Rect {
width: u32,
height: u32,
}
fn area(rect: &Rect) -> u32 {
rect.width * rect.height
}
let rect = Rect {
width: 100,
height: 100,
};
println!("area: {}", area(rect)); // area: 10000
复制代码
通过派生 trait 增加实用功能
上面有一个问题没有介绍,比如我们尝试直接打印完整结构体:
struct User {
name: String,
age: i32,
}
let user = {
name: String::from("xiao_ming"),
age: 10
};
println!("{}", user); // 报错,User无法使用默认格式化程序进行格式化
复制代码
解决这个问题需要两步,第一步,需要添加注解来派生 Debug trait:
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
复制代码
第二步,添加:?到花括号中,它会告知 println! 当前的结构体需要使用名为 Debug 的格式化输出:
println!("{:?}", user); // User { name: "xiao_ming", age: 10 }
复制代码
使用:#?占位符来增加易读性:
println!("{:?}", user);
// User {
// name: "xiao_ming",
// age: 10
// }
复制代码
实际上,rust 提供了许多可以通过 derive 注解来派生的 trait,它们可以为自定义的类型增加许多有用的功能,更多信息可以查阅官方文档。
评论