写点什么

每日一 R「07」类型系统(一)

作者:Samson
  • 2022 年 8 月 15 日
    上海
  • 本文字数:1829 字

    阅读完需:约 6 分钟

每日一R「07」类型系统(一)

在前面的课程中,我们学习了变量所有权、借用以及生命周期等 Rust 中非常重要且比较难懂的内容。今天我们将开始跟着老师一起学习 Rust 中的类型系统。

01-类型系统基本概念

从机器码角度是不存在类型的,与指令交互的是寄存器或内存中的数据流。


类型系统是高级语言中的概念,它是对值的区分,包含了值在内存中的长度、对齐方式以及值允许的操作方式等。因此,类型系统可以看作是一种工具,在编译期的静态检查和运行期的动态检查中,来保证处理的数据是开发者期望的类型。


类型系统是对类型进行定义、检查和处理的系统。类型系统可以划分为:


  • 按定义后类型是否可以隐式转换,类型系统可分为强类型系统和弱类型系统,前者不允许隐式转换,后者允许隐式转换。

  • 按照类型检查的时机,可以分为静态类型系统和动态类型系统,前者检查发生在编译期,后者检查发生在运行期。


类型系统中有一个非常重要的概念,多态,即在使用相同类型的接口时,不同类型的对象,会采用不同的实现。不同的类型系统实现多态的方式也不尽相同:


  • 对于动态类型系统,多态通过鸭子类型(duck type)实现。

  • 对于静态类型系统,多态通过参数多态、特设多态和子类型多态实现。

  • 其中,参数多态指,函数操作的是满足某个约束(例如实现了某个 trait)的参数,而非具体的类型;

  • 特设多态是指同一种行为(例如加法)可以有多个不同实现的多态,例如面向对象语言中的重载;

  • 子类型多态指运行时子类型可以被当成父类型使用,例如面向对象语言中的里氏替换原则

01.1-Rust 中多态是如何实现的

Rust 是一个静态强类型语言,它对参数多态的支持通过泛型来实现,对特设多态的支持通过 trait 来实现,对子类型多态的支持通过 trait object 来实现。


类型安全,从内存角度看,是指代码只能按照被允许的方法、访问它被授权访问的内存。Rust 下,类型安全有更严格地限制,即代码只能按照被允许的方法和被允许的权限,访问它被授权访问的内存。


为实现如此严格的要求,Rust 中规定一切代码块(出了 let 等定义性语句外)都是表达式。表达式是有类型的,所以类型无处不在。表达式是能够计算出值的,那下面这段表达式的值是什么?


if something_true {    do_corresponding_work();}
if something_ture { do_corresponding_work(); 30}
复制代码


Rust 中表达式的值是代码块中最后一个表达式的值。上述代码中,第一个 if 的返回值是 ()。() 是 Rust 中的一个特别的元素,也称为 unit,它的类型为 (),值也为 (),且在内存中并不占空间。第二个 if 的返回值是 30。

02-泛型(参数多态)

02.1-泛型数据结构

常见的泛型数据结构:Option<T>、Result<T, E>、Cow<T>


pub enum Option<T> {    None,    Some(T),}pub enum Result<T, E> {    Ok(T),    Err(E),}pub enum Cow<'a, T> where    T: 'a + ToOwned + ?Sized,  {    Borrowed(&'a T),    Owned(<T as ToOwned>::Owned),}
复制代码


Option<T> 中的 T 未作任何约束,即任何类型都可以。 Cow<T> 中 B 是有约束的,出了必须具备申明周期 ‘a 外,还需要满足:实现了 ToOwned trait,可以是 ?Size 可变大小的类型。

02.2-泛型函数

struct Point<T, U> {    x: T,    y: U,}
impl<T, U> Point<T, U> { fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> { Point { x: self.x, y: other.y, } }}
复制代码


与泛型数据结构一样,泛型参数需要提前声明,即 impl<T, U>。此时的 Point<T, U> 已不再是泛型声明,而是一个具体的数据结构。

02.3-单态化

Rust 在编译期间会将泛型转换为具体地类型,这个过程称为单态化。单态化是一个通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。正是单态化使得 Rust 运行时的效率不会丧失,但同时带来的是编译时间变长、可执行文件体积变大。


以标准库中 Option<T> 为例,如果按照如下方式使用:


let integer = Some(5);let float = Some(5.0);
复制代码


经过编译编译,会产生如下对应的代码,这个过程就是单态化过程:


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);}
复制代码


本节课程链接:《12|类型系统:Rust的类型系统有什么特点?


历史文章推荐

每日一 R「06」内存管理

每日一 R「05」生命周期

每日一 R「04」常用的智能指针

每日一 R「03」Borrow 语义与引用

每日一 R「02」所有权与 Move 语义

每日一 R「01」跟着大佬学 Rust

发布于: 1 小时前阅读数: 9
用户头像

Samson

关注

还未添加个人签名 2019.07.22 加入

还未添加个人简介

评论

发布
暂无评论
每日一R「07」类型系统(一)_8月月更_Samson_InfoQ写作社区