什么是类型系统,又为什么需要它呢?
学过计算机基础的小伙伴们都知道,我们用计算机编写的程序在最底层是以 0 和 1 的二进制组合表示的。实际上,最早的计算机系统也是大佬们通过手动编写机器码实现的,当时的大佬们肯定发现了,这太没意思了,又耗时间、还容易出错。于是在上世纪50年代的时候,有了汇编码。紧接着,编程语言出现了,它们能被编译为汇编码,允许程序员编写人类可读但易于计算机编译的代码,但是呢,我们人类说的语言总是模棱两可的,所以又需要设置一套规则和约束,这就有了类型和类型系统的概念。
类型为我们提供了一种表达实体的意图、行为和约束的方法。类型系统定义了我们可以对类型做什么,不能做什么,控制着不同类型在同一个编程语言中相互交流。
强类型、弱类型和静态类型、动态类型
我们平常说的强类型、弱类型,这个“强”可以理解为Robust,强壮的,意味着它在编译期执行更多的类型检查。
而静态类型是指,一个类型不会在运行时转换为其他类型。例如绑定为整数值的变量,以后不能动态地更改,指向字符串。
Rust正是一种,强类型、静态类型的语言。用Rust编写的的代码鲁棒性强,在运行期间不会动态变化。
泛型
之前学习过Java,都说Java的泛型是一种伪泛型。那么泛型是什么呢?
从高级编程语言的诞生开始,追求更好的抽象就是语言设计者一直努力追求的东西。因此,出现了许多关于代码复用(偷懒)的想法。
想想一下如果你编写了一个函数,比如avg,它用来计算给定整数值列表的平均值,然后你有一个用例,你也需要计算float值列表的平均值,通常的解决方案是创建一个新的函数,它可以从浮点数列表中平均浮点数值。但是如果现在又想接受一个Double值的列表呢?你肯定嫌烦了,该偷个懒了。对于程序员来说,反复编写仅仅是参数不同的相同函数就是浪费生命。为了减少这种重复,让avg这样的函数以一种能够接受多种类型的方式编写,泛型诞生了。
泛型编程只适用于静态类型编程语言。动态语言,例如Python就不能使用泛型。
使用泛型技术,就可以为类型的占位符编写函数、方法、类型,然后指定一个类型变量(使用单个字母,惯例通常是T、K或V ),告诉编译器稍后在代码实例化实际类型时填充实际类型。这些类型被称为泛型类型。
来自标准库的 Vec类型 就是一个泛型类型,定义如下:
pub struct Vec<T> {
buf: RawVec<T>,
len: usize,
}
如果我们的泛型类型Vec上没有T,编译器会告诉我们出现以下错误:
error[E0412]: cannot find type `T` in this scope
Traits
Traits可以被翻译为特质,他其实类似于Java里面的Interface,表示的是一种契约,行为规范。
Traits本身是不可用的,它应该通过类型来实现。Traits 能够建立不同类型之间的关系。当我们想要创建一个媒体播放器应用软件的时候,有音乐播放器和视频播放器两种,显然这两种播放器一定具备播放和关闭的函数/功能,此时我们就可以用trait来定义播放和关闭的功能。播放器实现这些功能。
trait Playable{
fn play(&self);
fn close(&self);
}
struct Audio(String);
struct Music(String);
impl Playable for Audio {
fn play(&self) {
println!("播放视频")
}
fn close(self: &Self) {
println!("关闭视频")
}
}
impl Playable for Music {
fn play(&self) {
println!("播放音乐")
}
fn close(&self) {
println!("关闭音乐")
}
}
fn main() {
let audio = Audio("a".to_string());
audio.play();
audio.close()
}
注意:trait里面的函数必须全部实现,这是契约。