0x00 开篇
上一篇文章简单介绍了泛型,本篇文章将继续介绍泛型的相关概念——泛型结构体。在介绍泛型结构体前,还需要先介绍下如何在结构体中定义方法,以及泛型方法。本篇文章也算作是对结构体章节的一个补充。
0x01 方法与函数
方法表示某个类型实例的行为,方法与函数的定义大同小异。在前面文章中,不知道你有没有发现,函数和方法这两个词都出现过。在结构体中,方法必须定义在 impl 块中。方法要求第一个参数必须是 &self 或者是 &mut self,这也是与函数的唯一区别。在方法中,使用 &self 读取实例中的数据,使用 &mut self 可以读写实例中的数据。
0x02 在结构体中定义方法
先上代码,后解释。
struct Person { // 名字 name: String, // 年龄 age: u8, } impl Person { // 方法 fn get_age(&self) -> u8 { return self.age; } fn set_age(&mut self, age: u8) { self.age = age; } fn get_name(&self) -> &str { return self.name.as_str(); } fn set_name(&mut self, name: &str) { self.name = name.to_string(); } //关联函数 fn to_string(person: Person) -> String { return format!("Person {{ name: {}, age: {} }}", person.get_name(), person.get_age()); } } fn main() { let mut person = Person { name: String::from("test"), age: 8, }; println!("修改前:name: {}, age: {}", person.get_name(), person.get_age()); person.set_name("张三"); person.set_age(18); println!("修改后:name: {}, age: {}", person.get_name(), person.get_age()); // 通过关联函数输出 println!("{}", Person::to_string(person)) // 输出结果: // 修改前:name: test, age: 8 // 修改后:name: 张三, age: 18 // Person { name: 张三, age: 18 } }
首先我们定义一个结构体 _Person_,我们通过 impl 为其添加方法。其中,所有方法的第一个参数都是 &self 或者是 &mut self。在 impl 块中,我们定义了 get_age,set_age,get_name,set_name 四个方法。再看 main 函数块内,我们可以通过“实例名.方法名”的语法来调用方法。调用方法时,不需要传递 self 参数,self 参数将由编译器自动传递。另外,我们还在结构体内定义了一个关联函数 to_string 来打印内容。我们通过 “结构体名::函数名”的语法来调用结构体内的关联函数。
0x03 泛型结构体
结构体也可以是泛型的,换句话讲,我们可以使用泛型写一个通用的结构体模板。前面介绍的 Vec 向量就是一个泛型结构体类型,这种结构体可以插入任何数据类型,我们下面以自定义一个“队列”来介绍泛型结构体,先上代码。
/// 定义一个队列 struct Queue<T> { // 通过向量存储数据 data: Vec<T>, // 队列的长度 size: u32, } /// 定义队列的方法 impl<T> Queue<T> { /// 创建一个队列 /// 这是一个关联函数 pub fn new() -> Queue<T> { Queue { data: vec![], size: 0, } } /// 向队列中插入一个值 /// 这是一个方法 pub fn offer(&mut self, value: T) { self.data.push(value); self.size += 1; } /// 弹出队列的最顶部的元素 /// 这是一个方法 pub fn poll(&mut self) { if self.size > 0 { self.data.remove(0); self.size -= 1; } } } fn main() { let mut queue: Queue<i32> = Queue::new(); queue.offer(4); queue.offer(7); queue.offer(10); println!("队列的长度:{}", queue.size); queue.poll(); queue.poll(); queue.poll(); queue.offer(10); println!("队列的长度:{}", queue.size); // 输出结果: // 队列的长度:3 // 队列的长度:1 }
首先定义一个队列结构体 Queue,定义结构体时,需要在结构体名称后面加上泛型的标签。我们借助向量来存储数据,再额外维护一个队列的长度 size 变量,简单的队列就定义完成。接着定义队列的方法,这里与普通的结构体方法略有不同,我们定义泛型结构体时,需要在 impl 后面加上泛型的标签,然后再跟结构体的名称。在impl 块中,我们分别实现了创建一个队列的关联函数(new)和数据入队(offer),数据出队两个方法(poll)。
0x04 泛型方法
定义:带有泛型类型的参数或者是返回值的方法叫做泛型方法。上面代码中的 offer 方法就是一个泛型方法。泛型方法与泛型函数类似,我就不做介绍了。
0x05 小结
通过两篇文章,介绍了泛型的概念与泛型相关的一些数据类型——泛型与向量,泛型函数,泛型枚举,泛型结构体, 泛型方法等。有关泛型的相关知识基本已经写完了,但是结构体还没有。结构体是 Rust 中很重要的数据类型,它也是 Rust 面向对象的特征中最重要的组成部分。