网站公司郑州,wordpress 小工具调用,广州服装网站建设,邯郸高端网站建设价格泛型是一个编程语言不可或缺的机制。
C 语言中用模板来实现泛型#xff0c;而 C 语言中没有泛型的机制#xff0c;这也导致 C 语言难以构建类型复杂的工程。
泛型机制是编程语言用于表达类型抽象的机制#xff0c;一般用于功能确定、数据类型待定的类#xf…
泛型是一个编程语言不可或缺的机制。
C 语言中用模板来实现泛型而 C 语言中没有泛型的机制这也导致 C 语言难以构建类型复杂的工程。
泛型机制是编程语言用于表达类型抽象的机制一般用于功能确定、数据类型待定的类如链表、映射表等。
在函数中定义泛型
这是一个对整型数字选择排序的方法
实例
fn max(array: [i32]) - i32 {let mut max_index 0;let mut i 1;while i array.len() {if array[i] array[max_index] {max_index i;}i 1;}array[max_index]
}fn main() {let a [2, 4, 6, 3, 1];println!(max {}, max(a));
}
运行结果
max 6
这是一个简单的取最大值程序可以用于处理 i32 数字类型的数据但无法用于 f64 类型的数据。通过使用泛型我们可以使这个函数可以利用到各个类型中去。但实际上并不是所有的数据类型都可以比大小所以接下来一段代码并不是用来运行的而是用来描述一下函数泛型的语法格式
实例
fn maxT(array: [T]) - T {let mut max_index 0;let mut i 1;while i array.len() {if array[i] array[max_index] {max_index i;}i 1;}array[max_index]
}
结构体与枚举类中的泛型
在之前我们学习的 Option 和 Result 枚举类就是泛型的。
Rust 中的结构体和枚举类都可以实现泛型机制。
struct PointT {x: T,y: T
}
这是一个点坐标结构体T 表示描述点坐标的数字类型。我们可以这样使用
let p1 Point {x: 1, y: 2};
let p2 Point {x: 1.0, y: 2.0};
使用时并没有声明类型这里使用的是自动类型机制但不允许出现类型不匹配的情况如下
let p Point {x: 1, y: 2.0};
x 与 1 绑定时就已经将 T 设定为 i32所以不允许再出现 f64 的类型。如果我们想让 x 与 y 用不同的数据类型表示可以使用两个泛型标识符
struct PointT1, T2 {x: T1,y: T2
}
在枚举类中表示泛型的方法诸如 Option 和 Result
enum OptionT {Some(T),None,
}enum ResultT, E {Ok(T),Err(E),
}
结构体与枚举类都可以定义方法那么方法也应该实现泛型的机制否则泛型的类将无法被有效的方法操作。
实例
struct PointT {x: T,y: T,
}implT PointT {fn x(self) - T {self.x}
}fn main() {let p Point { x: 1, y: 2 };println!(p.x {}, p.x());
}
运行结果
p.x 1
注意impl 关键字的后方必须有 T因为它后面的 T 是以之为榜样的。但我们也可以为其中的一种泛型添加方法
impl Pointf64 {fn x(self) - f64 {self.x}
}
impl 块本身的泛型并没有阻碍其内部方法具有泛型的能力
implT, U PointT, U {fn mixupV, W(self, other: PointV, W) - PointT, W {Point {x: self.x,y: other.y,}}
}
方法 mixup 将一个 PointT, U 点的 x 与 PointV, W 点的 y 融合成一个类型为 PointT, W 的新点。 特性
特性trait概念接近于 Java 中的接口Interface但两者不完全相同。特性与接口相同的地方在于它们都是一种行为规范可以用于标识哪些类有哪些方法。
特性在 Rust 中用 trait 表示
trait Descriptive {fn describe(self) - String;
}
Descriptive 规定了实现者必需有 describe(self) - String 方法。
我们用它实现一个结构体
实例
struct Person {name: String,age: u8
}impl Descriptive for Person {fn describe(self) - String {format!({} {}, self.name, self.age)}
}
格式是
impl 特性名 for 所实现的类型名
Rust 同一个类可以实现多个特性每个 impl 块只能实现一个。
默认特性
这是特性与接口的不同点接口只能规范方法而不能定义方法但特性可以定义方法作为默认方法因为是默认所以对象既可以重新定义方法也可以不重新定义方法使用默认的方法
实例
trait Descriptive {fn describe(self) - String {String::from([Object])}
}struct Person {name: String,age: u8
}impl Descriptive for Person {fn describe(self) - String {format!({} {}, self.name, self.age)}
}fn main() {let cali Person {name: String::from(Cali),age: 24};println!({}, cali.describe());
}
运行结果
Cali 24
如果我们将 impl Descriptive for Person 块中的内容去掉那么运行结果就是
[Object]
特性做参数
很多情况下我们需要传递一个函数做参数例如回调函数、设置按钮事件等。在 Java 中函数必须以接口实现的类实例来传递在 Rust 中可以通过传递特性参数来实现
fn output(object: impl Descriptive) {println!({}, object.describe());
}
任何实现了 Descriptive 特性的对象都可以作为这个函数的参数这个函数没必要了解传入对象有没有其他属性或方法只需要了解它一定有 Descriptive 特性规范的方法就可以了。当然此函数内也无法使用其他的属性与方法。
特性参数还可以用这种等效语法实现
fn outputT: Descriptive(object: T) {println!({}, object.describe());
}
这是一种风格类似泛型的语法糖这种语法糖在有多个参数类型均是特性的情况下十分实用
fn output_twoT: Descriptive(arg1: T, arg2: T) {println!({}, arg1.describe());println!({}, arg2.describe());
}
特性作类型表示时如果涉及多个特性可以用 符号表示例如
fn notify(item: impl Summary Display)
fn notifyT: Summary Display(item: T)
注意仅用于表示类型的时候并不意味着可以在 impl 块中使用。
复杂的实现关系可以使用 where 关键字简化例如
fn some_functionT: Display Clone, U: Clone Debug(t: T, u: U)
可以简化成
fn some_functionT, U(t: T, u: U) - i32where T: Display Clone,U: Clone Debug
在了解这个语法之后泛型章节中的取最大值案例就可以真正实现了
实例
trait Comparable {fn compare(self, object: Self) - i8;
}fn maxT: Comparable(array: [T]) - T {let mut max_index 0;let mut i 1;while i array.len() {if array[i].compare(array[max_index]) 0 {max_index i;}i 1;}array[max_index]
}impl Comparable for f64 {fn compare(self, object: f64) - i8 {if self object { 1 }else if self object { 0 }else { -1 }}
}fn main() {let arr [1.0, 3.0, 5.0, 4.0, 2.0];println!(maximum of arr is {}, max(arr));
}
运行结果
maximum of arr is 5
Tip: 由于需要声明 compare 函数的第二参数必须与实现该特性的类型相同所以 Self 注意大小写关键字就代表了当前类型不是实例本身。
特性做返回值
特性做返回值格式如下
实例
fn person() - impl Descriptive {Person {name: String::from(Cali),age: 24}
}
但是有一点特性做返回值只接受实现了该特性的对象做返回值且在同一个函数中所有可能的返回值类型必须完全一样。比如结构体 A 与结构体 B 都实现了特性 Trait下面这个函数就是错误的
实例
fn some_function(bool bl) - impl Descriptive {if bl {return A {};} else {return B {};}
}
有条件实现方法
impl 功能十分强大我们可以用它实现类的方法。但对于泛型类来说有时我们需要区分一下它所属的泛型已经实现的方法来决定它接下来该实现的方法
struct AT {}implT: B C AT {fn d(self) {}
}
这段代码声明了 AT 类型必须在 T 已经实现 B 和 C 特性的前提下才能有效实现此 impl 块。