湘潭网站建设出色磐石网络网站搭建详细教程
news/
2025/9/29 20:14:24/
文章来源:
湘潭网站建设出色磐石网络,网站搭建详细教程,wordpress页面固定链接修改,网站前台用什么开发泛型#xff0c;英文是generic。 泛型是一种参数化多态。就是把类型作为参数#xff0c;使用时才指定具体类型。 这样一套代码可以应用于多种类型。比如VecT#xff0c;可以是整型向量Veci32#xff0c;也可以是浮点型向量Vecf64。
Rust中的泛型属…泛型英文是generic。 泛型是一种参数化多态。就是把类型作为参数使用时才指定具体类型。 这样一套代码可以应用于多种类型。比如VecT可以是整型向量Veci32也可以是浮点型向量Vecf64。
Rust中的泛型属于静多态它是一种编译期多态。 在编译期会根据指定的具体类型生成一套特化代码这叫单态化。比如将一个泛型函数生成具体类型对应的函数。 单态化是编译器进行静态分发的一种策略。 单态化静态分发的好处就是性能好没有运行时开销缺点就是造成编译后生成的二进制文件膨胀。
一、定义泛型
语法格式 T T就是泛型参数。
一在函数中使用泛型 使用了泛型的函数就叫泛型函数 1.语法格式 泛型函数的定义语法如下
fn function_nameT[:trait_name](param1:T, [other_params]) {// 函数实现代码
}实例
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]
}二在结构体中使用泛型 使用了泛型的结构体叫做泛型结构体 1.语法格式 泛型结构体的定义语法如下
struct struct_nameT {field:T
}例子
struct PointT {x: T,y: 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};2.在结构体的实现块中使用泛型 语法格式
implT PointT {
}注意impl关键字的后方必须有 T因为PointT要以它为实参。
实例
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 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的新点。
三在枚举中使用泛型 使用了泛型的枚举叫泛型枚举 诸如Option和Result
enum OptionT {Some(T),None
}enum ResultT, E {Ok(T),Err(E)
}四在trait中使用泛型
struct AS {}
trait ATT {fn foo(self, para: T);
}impl ATString for AS{fn foo(self, para: String){}
}五在别名中使用泛型 比如
type IoResultTResultT, IoError;二、泛型参数约束
1.trait约束 限制参数为必须实现了某个特性
范例 传递的参数必须是实现了Display特性的类型。
use std::fmt::Display;
fn main(){print_pro(10 as u8);print_pro(20 as u16);print_pro(Hello TutorialsPoint);
}
fn print_proT:Display(para:T){println!(Inside print_pro generic function:);println!({},para);
}
编译运行结果如下
Inside print_pro generic function:
10
Inside print_pro generic function:
20
Inside print_pro generic function:
Hello TutorialsPoint2.多重约束 使用 比如
fn notifyT: Summary Display(item: T){}实例
struct StructAT {}
implT: TraitB TraitC StructAT {fn d(self) {}
}StructAT类型必须在T已经实现B和C特性的前提下才能实现此impl块。
3.使用where关键字简写约束 约束也可以使用where分句来表达它放在 { 的前面。
例如
fn some_functionT: Display Clone, U: Clone Debug(t: T, u: U){
}可以简化成
fn some_functionT, U(t: T, u: U) - i32
where
T: Display Clone,
U: Clone Debug,{
}下面的impl如果不用where从句就无法直接表达。
use std::fmt::Debug;
trait PrintInOption {fn print_in_option(self);
}
// 这里需要一个 where 从句否则就要表达成 T: Debug这样意思就变了
// 或者改用另一种间接的方法。
implT PrintInOption for T
where
OptionT: Debug {// 我们要将 OptionT: Debug 作为约束因为那是要打印的内容。// 否则我们会给出错误的约束。fn print_in_option(self) {println!({:?}, Some(self));}
}
fn main() {let vec vec![1, 2, 3];vec.print_in_option();
}三、泛型参数默认值
1.当使用泛型时可以为泛型参数指定一个默认的具体类型。 语法 PlaceholderTypeConcreteType这种情况的一个非常好的例子是运算符重载。运算符重载是指自定义运算符比如 的行为。 Rust并不允许创建自定义运算符或重载任意运算符不过std::ops中所列出的运算符和相应的trait可以通过实现运算符相关trait来重载。 例如下例展示了如何在Point结构体上实现Add trait来重载 运算符这样就可以将两个Point实例相加了
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Point {x: i32,y: i32,
}
impl Add for Point {type Output Point;fn add(self, other: Point) - Point {Point {x: self.x other.x,y: self.y other.y,}}
}
fn main() {assert_eq!(Point { x: 1, y: 0 } Point { x: 2, y: 3 },Point { x: 3, y: 3 });
}add方法将两个Point实例的x值和y值分别相加来创建一个新的Point。
Add定义如下
trait AddRHSSelf {type Output;fn add(self, rhs: RHS) - Self::Output;
}RHSSelfSelf就是泛型参数默认值它表示实现Add的类型在这里就是Point类型。如果实现Add时不指定RHS的具体类型RHS的类型将是Self类型。
2.不使用默认类型的例子。 我们希望能够将毫米值与米值相加并让Add的实现正确处理转换。可以为Millimeters实现Add并以Meters作为RHS
use std::ops::Add;
struct Millimeters(u32);
struct Meters(u32);
impl AddMeters for Millimeters {type Output Millimeters;fn add(self, other: Meters) - Millimeters {Millimeters(self.0 (other.0 * 1000))}
}为了使Millimeters和Meters能够相加我们使用AddMeters而不是使用默认的Add。
四、泛型代码的性能
Rust通过在编译时单态化来保证效率。单态化是一个通过填充编译时使用的具体类型将通用代码转换为特定代码的过程。 编译器寻找所有泛型代码被调用的位置并针对具体类型生成特化代码。 例子
let integer Some(5);
let float Some(5.0);当Rust编译这些代码的时候它会单态化。编译器会读取传递给OptionT的值并发现有两种OptionT一个对应i32另一个对应f64。为此它会将泛型定义OptionT展开为两个针对i32和f64的定义接着将泛型定义替换为这两个具体的定义。 编译器生成的单态化代码看起来像这样
enum Option_i32 {Some(i32),None,
}
enum Option_f64 {Some(f64),None,
}
fn main() {let integer Option_i32::Some(5);let float Option_f64::Some(5.0);
}OptionT被编译器替换为了具体的定义。因为Rust会将每种情况下的泛型代码编译为具体类型使用泛型没有运行时开销。当代码运行时它的执行效率就跟好像手写每个具体定义的重复代码一样。这个单态化过程正是Rust泛型在运行时极其高效的原因。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/922219.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!