本文作为对Rust的基础学习,建议每一位对Rust感兴趣并且想要接触Rust的同学,将本文中所有例子都自己运行一遍,不要求你手动重写,至少将例子复制下来运行查看效果。
本文基于:
rust: 1.67.0 (fc594f156 2023-01-24)
cargo: 1.67.0 (8ecd4f20a 2023-01-10)
参考文档:Rust 程序设计语言 简体中文版
Rust中的泛型
泛型的概念几乎在每个高级语言中都有,为代码增加泛型的目的其实就是为了更高效的处理重复逻辑;初次接触泛型的人可能会对程序中出现的大类
<T>、<P>、<M>等,头大,或者看不懂,不理解;可当一旦熟练使用泛型之后,说是
如鱼得水也不为过。文档中的赘述有点多,这里尽量使用通俗的话来讲解;首先,看下面的例子:
fn main() { let arr = [1, 2, 3, 4, 5]; let v = vec![1.1, 2.0, 3.5]; print_list(&arr[..]); print_list(&v[..]); } //循环输出一个列表 fn print_list<T>(list: &[T]) { for it in list { print!("{}、 ", it); } println!(); }上述示例,定义了一个名为:
print_list的函数,函数功能则是遍历输出某个列表切片,并且在main中对它进行调用。按照逻辑,它应该输出结果:
1、 2、 3、 4、 5、 1.1、 2、 3.5、但是,本文所依赖的运行环境会出现错误提示(旧环境无法考究),
error[E0277]: `T` doesn't implement `std::fmt::Display` --> src\main.rs:11:24 | 11 | print!("{}、 ", it); | ^^ `T` cannot be formatted with the default formatter | = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the macro `print` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 9 | fn print_list<T: std::fmt::Display>(list: &[T]) { |依照提示,为其加上
: std::fmt::Display即可:fn main() { let arr = [1, 2, 3, 4, 5]; let v = vec![1.1, 2.0, 3.5]; print_list(&arr[..]); print_list(&v[..]); } fn print_list<T: std::fmt::Display>(list: &[T]) { for it in list { print!("{}、 ", it); } println!(); }这样就可以成功运行看到前文所说的结果了。
说回来泛型,可以看到
print_list<T>增加了一个<T>,并且参数list:&[T]中也将T使用了,那么这个<T>可以将它看做类型通配符,即<T>可以是任意类型,正如main函数中的两次调用,一个是i32数组的切片&[i32],一个是f64vector的切片&[f64],它们类型不同,却又都调用了print_list函数。再说得简单一点:
print_list<T>可以是print_list<i32>也可以是print_list<f64>或者说其他的print_list<char>等等。这既是泛型最通俗的解释,至于何时使用泛型,则需要根据程序中相应的情况来看,比如Rust文档中的
Point结构体,通俗逻辑下x,y坐标可以是整数也可以是小数,如果不通过泛型,那至少应该写两个Point结构:struct PointF { x: f64, y: f64, } struct PointI { x: i32, y: i32, }而泛型的出现,让它更加简单了,同时也少写了一遍除了数据类型不同,其他都相同的代码:
struct Point<T> { x: T, y: T, }Rust中的Trait(接口)
编程中,接口的概念其实就是定义了一套行为规范,用通俗的话来讲,就是给了你一套图纸,你可以通过这套图纸来设计你的程序;Rust中,通过Trait定义一套行为规范(设计图纸),然后你就可以将图纸交给任意一个开发者,让他来遵循图纸来设计程序。
例如:对于汽车来说,汽车最基本的功能就是能
跑,那么,我们可以给一个顶层的行为run,每一台汽车都应该具有run的功能:pub trait Car { fn run(&self); }上述代码中,
Car是由trait修饰的,它提供了一个方法run,却没有方法体(可以将它看做C语言中的函数声明),这就是汽车的最简单图纸,一旦按照这个图纸设计汽车,run则是必不可少的功能。现在我们来造一辆SUV:
struct Suv { name: String, } impl Car for Suv { fn run(&self) { println!("{}, 行驶中..", self.name); } }上述代码实现了
trait Car的基本功能,可以看到Rust中对于接口(trait)的实现与其他编程语言略有不同:impl 接口(trait) for 结构体(struct){ ... }。不过它有一点却与其他编程语言类似,也就是
方法的抽象性:- 当
trait中的某些方法没有方法体时,实现该trait的结构则必须提供方法体。
pub trait Car { fn run(&self){ println!("行驶中..."); } } struct Suv { name: String, } impl Car for Suv { //如果基本功能满足, 则可以省略 /* fn run(&self) { println!("{}, 行驶中..", self.name); } */ }接口与多态一旦涉及到接口,必定会有一个多态性,通俗来讲,大众被称为汽车,宝马也被称为汽车。
fn main() { let suv = Suv { name: "大众".to_string(), }; let bwm = Bwm { name: "宝马".to_string(), }; who_run(&suv); who_run(&bwm); } //到底是谁在运行 fn who_run(car: &impl Car) { car.run(); } // pub trait Car { fn run(&self); } struct Suv { name: String, } impl Car for Suv { fn run(&self) { println!("{}, 行驶中..", self.name); } } struct Bwm { name: String, } impl Car for Bwm { fn run(&self) { println!("{}, 行驶中..", self.name); } }输出:
大众, 行驶中.. 宝马, 行驶中..同样的,可以用泛型直接指代(我个人更趋向于这种写法)文档称它为
trait bound://到底是谁在运行 fn who_run<T: Car>(car: &T) { car.run() }trait多实现fn main() { let suv = Suv { name: "大众".to_string(), }; let bwm = Bwm { name: "宝马".to_string(), }; who_run(&suv); who_run(&bwm); } //到底是谁在运行 fn who_run<T: Car + Color>(car: &T) { car.run(); car.color(); } // pub trait Car { fn run(&self); } pub trait Color { fn color(&self); } struct Suv { name: String, } impl Car for Suv { fn run(&self) { println!("{}, 行驶中..", self.name); } } impl Color for Suv { fn color(&self) { println!("红色"); } } struct Bwm { name: String, } impl Car for Bwm { fn run(&self) { println!("{}, 行驶中..", self.name); } } impl Color for Bwm { fn color(&self) { println!("紫色"); } }上述代码中又给定了一个
Trait Color,并分别让Suv和Bwm实现;然后在
fn who_run<T: Car + Color>(car: &T)通过+的方式,对多实现结构进行操作。对于Rust中
trait的介绍暂时到这,文档中提到的闭包将在闭包一节介绍。- 当
时间:2023年2月15日 第7天