本教程环境
系统:MacOS
Rust 版本:1.77.2
Rust 结构体用来进行自定义数据类型的定义。 Rust 有三种结构体类型:具名字段型结构体、元组型结构体、单元型结构体。
具名字段型结构体
定义一个用户信息结构体。
rust
fn main() {
let user1 = User {
active: true,
username: String::from("frank"),
email: String::from("example@xx.com"),
sign_in_count: 1
};
println!("user1: {:?}", user1);
// user1: User { active: true, username: "frank", email: "example@xx.com", sign_in_count: 1 }
println!("user1 name: {}", user1.username); // user1 name: frank
let username = "John".to_string();
let mut user2 = User {
username,
..user1
};
user2.sign_in_count = 2;
println!("user2: {:?}", user2);
// user2: User { active: true, username: "John", email: "example@xx.com", sign_in_count: 2 }
}
#[derive(Debug)]
#[allow(dead_code)]
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64
}
Rust 中结构体类型都是需要驼峰式书写。字段和方法是小写,单词用下划线分割。 如果局部变量或参数与结构体字段同名,可进行简写。 访问结构体字段需要使用 .
运算符。 创建具名结构体值时,可以从另一个相同类型的结构体中为省略的字段提供值。需要使用 ..
表达式。
元组型结构体
rust
struct Bounds(usize, usize);
它保存的值称为元素,通过下标进行访问。 元组型结构体适用于创造新类型,即建立一个包含单组件的结构体,以获得更严格的类型检查。
单元型结构体
没有元素的结构体类型。
rust
struct Onesuch;
这种类型的值不占用内存,很像单元类型 ()
。Rust 既不会在内存中实际存储单元类型结构体的值,也不会生成代码来对它们进行操作,因为仅通过值的类型它就能知道关于值的所有信息。
用 impl 定义方法
使用 impl 为结构体定义方法。
rust
pub struct Queue {
older: Vec<char>,
younger: Vec<char>,
}
impl Queue {
pub fn push(&mut self, c: char) {
self.younger.push(c);
}
pub fn pop(&mut self) -> Option<char> {
if self.older.is_empty() {
if self.younger.is_empty() {
return None;
}
use std::mem::swap;
swap(&mut self.older, &mut self.younger);
self.older.reverse();
}
self.older.pop()
}
}
impl
块中定义的函数称为 关联函数 。也就是结构体方法。 Rust 会将调用关联函数的结构体值作为第一个参数传给方法,改参数具有特殊名称 self
,是 self: &Self
的简写。如果是可变引用写成 &mut self
,是 self: &mut Self
的简写。Self
指的结构体本身的类型。
以 Box、Rc 或 Arc 形式传入 self
方法的 self
参数也可以是 Box<Self>
类型、Rc<Self>
类型或 Arc<Self>
类型。这种方法只能在给定的指针类型上调用。调用该方法会将指针的所有权传给它。 但是通常不需要这么做。一个方法期望通过引用接受 self
,那它在任何指针类型上调用时都可以正常工作。
rust
let mut bq = Box::new(Queue::new());
// Queue::push 需要一个 &mut self,但 bq 是一个 Box<Queue>
// 这没有问题,Rust 在调用期间从 Box 借入了 &mut Queue
bq.push('a');
对于方法调用和字段访问,Rust 会自动从 Box
、Rc
、Arc
等指针类型中借入引用,因此 &self
和 &mut self
几乎总是方法签名里的正确选择。 但是如果某些方法确实需要获取指向 Self
的指针的所有权,并且其调用者手头恰好有这样一个指针,那么 Rust 允许你将它作为方法的 self 参数传入。此时,必须写出 self
的类型。
rust
impl Node {
fn append_to(self: Rc<Self>, parent: &mut Node) {
parent.children.push(self);
}
}
类型关联函数
不接收 self
参数的方法,叫做类型关联函数。 例如定义一个构造函数,通常叫做 new
,或者 with_capacity
等。
rust
impl Queue {
pub fn new() -> Queue {
Queue { older: Vec::new(), younger: Vec::new() }
}
}
关联常量
与类型关联的值叫做关联常量。
rust
pub struct Vector2 {
x: f32,
y: f32,
}
impl Vector2 {
const ZERO: Vector2 = Vector2 { x: 0.0, y: 0.0 };
const UNIT: Vector2 = Vector2 { x: 1.0, y: 0.0 };
const NAME: &'static str = "Vector2";
const ID: u32 = 18;
}
这些值是和类型本身相关联的,可以在不引用 Vector2 的任一实例的情况下使用它们。
rust
let scaled = Vector2::UNIT.scaled_by(2.0);
泛型结构体
rust
pub struct Queue<T> {
older: Vec<T>,
younger: Vec<T>
}
impl<T> Queue<T> {
pub fn new() -> Queue<T> {
Queue { older: Vec::new(), younger: Vec::new() }
}
pub fn push(&mut self, t: T) {
self.younger.push(t);
}
pub fn is_empty(&self) -> bool {
self.older.is_empty() && self.younger.is_empty()
}
}
还能为特定类型实现方法:
rust
impl Queue<f64> {
fn sum(&self) -> f64 {
// ...
}
}
Self
指的是类型 Queue<T>
,所以可以将 new
构造函数修改。 调用关联函数的时候可以使用 ::<>
比目鱼操作符来指定类型参数。通常 Rust 能推断出来。
rust
let mut q = Queue::<char>::new();
带生命周期参数结构体
rust
struct Extrema<'elt> {
greatest: &'elt i32,
least: &'elt i32
}
可将 Extrema<'elt>
理解为:给定任意生命周期 'elt
,都可以创建一个 Extrema<'elt>
来持有对该生命周期的引用。 下面的函数会扫描切片并返回一个 Extrema
值,这个值的各个字段会引用其中的元素:
rust
fn find_extrema<'s>(slice: &'s [i32]) -> Extrema<'s> {
let mut greatest = &slice[0];
let mut least = &slice[0];
for i in 1..slice.len() {
if slice[i] < *least { least = &slice[i]; }
if slice[i] > *greatest { greatest = &slice[i]; }
}
Extrema { greatest, least }
}
带常量参数的泛型结构体
泛型结构体可接受常量值作为参数。定义一个表示任意次数多项式的类型:
rust
/// N - 1 次多项式
struct Polynomial<const N: usize> {
/// 多项式系数
///
/// "对于多项式a + bx + cx^2 + ... + zx^(n-1),其第`i`个元素是xi的系数"
coefficients: [f64; N]
}
<const N:usize>
子句表示 Polynomial
类型需要一个 usize
值作为它的泛型参数,以此来决定要存储多少个系数。Polynomial<3>
是一个二次多项式。 也可在类型的关联函数中使用参数 N
。
rust
impl<const N: usize> Polynomial<N> {
fn new(coefficients: [f64; N]) -> Polynomial<N> {
Polynomial { coefficients }
}
/// 计算 x 处的多项式的值
fn eval(&self, x: f64) -> f64 {
let mut sum = 0.0;
for i in (0..N).rev() {
sum = self.coefficients[i] + x * sum;
}
sum
}
}
如果结构体还接受其他种类的泛型参数,生命周期参数必须是第一,然后是类型,最后是 const
值。
让结构体类型实现某些公共特型(trait)
定义一个结构体 Point
类型,但是它不能打印,不支持比较。此时需要使用 Rust 特性。这些特型 Rust 已经实现了,可以使用 #[derive]
属性添加到结构体。
rust
#[derive(Copy, Clone, Debug, PartialEq)]
struct Point {
x: f64,
y: f64
}
内部可变性
需要一个不可变值中的一丁点可变数据,就是内部可变性。 Rust 提供了很多方案,两种直观的类型,即 Cell<T>
和 RefCell<T>
,都在 std::cell
模块中。 Cell<T>
是一个包含类型 T 的单个私有值的结构体。 Cell
唯一的特殊之处在于,即使对 Cell
本身没有 mut
访问权限,也可获取和设置这个私有值字段。
rust
Cell::new(value) // 新建
cell.get() // 获取
cell.set(value) // 设置
Cell 不允许在共享值上调用 mut 方法。.get()
方法会返回 Cell 中值的副本,因此它仅在 T 实现了 Copy 特型时才有效。 如果需要一个引用,需要使用 RefCell<T>
,支持借用对其 T 值的引用。
rust
RefCell::new(value) // 新建
ref_cell.borrow() // 借用
ref_cell.borrow_mut() // 可变借用
ref_cell.try_borrow() // 尝试借用
ref_cell.try_borrow_mut() // 尝试可变借用
教程代码仓库:github.com/zcfsmile/Ru...
参考链接:
🌟🌟 🙏🙏感谢您的阅读,如果对您有帮助,欢迎关注、点赞 🌟🌟