正式开端
- 在机器码的世界中,指令仅仅和立即数或许内存打交道,内存中寄存的数据都是字节省
- 类型体系完满是一种工具
类型体系基本概念与分类
- 类型:是对值的区别,它包含了值在内存中的长度、对齐以及值能够进行的操作等信息
- 类型体系其实便是,对类型进行界说、查看和处理的体系
分类
-
按界说后类型是否能够隐式转化,能够分为强类型和弱类型
-
按类型查看的机遇,在编译时查看仍是运行时查看,能够分为静态类型体系和动态类型体系
a. 对于静态类型体系,还能够进一步分为显式静态和隐式静态
多态
-
在运用相同的接口时,不同类型的对象,会采用不同的完成
-
对于动态类型体系,多态经过**鸭子类型(duck typing)**完成
-
对于静态类型体系,多态能够经过**参数多态(parametric polymorphism)、特设多态(adhoc polymorphism)和子类型多态(subtype polymorphism)**完成
a. 参数多态是指,代码操作的类型是一个满意某些束缚的参数,而非具体的类型。
b. 特设多态是指同一种行为有多个不同完成的多态。比如加法,能够 1+1,也能够是 “abc” + “cde”、matrix1 + matrix2、甚至 matrix1 + vector1。在面向对象编程言语中,特设多态一般指函数的重载
c. 子类型多态是指,在运行时,子类型能够被当成父类型运用
-
在 Rust 中,参数多态经过泛型来支撑、特设多态经过 trait 来支撑、子类型多态能够用 trait object 来支撑
Rust类型体系
- 在界说时, Rust 不答应类型的隐式转化,也便是说,Rust 是强类型言语;
- 在查看时,Rust 运用了静态类型体系,在编译期确保类型的正确
- 从内存的视点看,类型安满是指 代码只能按照被答应的办法和被答应的权限,拜访它被授权拜访的内存
Rust 中除了 let / fn / static / const 这些界说性句子外都是表达式,而一切表达式都有类型
在 Rust 中,对于一个效果域,无论是 if / else / for 循环仍是函数,最终一个表达式的回来值便是效果域的回来值,假如表达式或许函数不回来任何值,那么它回来一个 unit() 。unit 是只要一个值的类型,它的值和类型都是 ()
数据类型
- 在原生类型的基础上,Rust 标准库还支撑非常丰富的组合类型
- 类型分类
类型推导
- 在一个效果域之内,Rust 能够根据变量运用的上下文,推导出变量的类型
- collect 是 Iterator trait 的办法,它把一个 iterator 转化成一个调集
- 在泛型函数后运用 ::来强制运用类型 T,这种写法被称为 turbofish
- 有些情况下,即便上下文中含有类型的信息,也需求开发者为变量供给类型,比如常量和静态变量的界说
用泛型完成参数多态
泛型数据结构
泛型结构 Vec<T>
pub struct Vec<T, A: Allocator = Global> {
buf: RawVec<T, A>,
len: usize,
}
pub struct RawVec<T, A: Allocator = Global> {
ptr: Unique<T>,
cap: usize,
alloc: A,
}
/*
Vec有两个参数
一个是 T,是列表里的每个数据的类型
另一个是 A,它有进一步的束缚 A: Allocator ,也便是说 A 需求满意 Allocator trait
A 这个参数有默许值 Global,它是 Rust 默许的大局分配器
*/
枚举类型 Cow
生命周期标注也是泛型的一部分,一个生命周期 ‘a 代表恣意的生命周期,和 T 代表恣意类型是相同的
/*
这儿对B 的三个束缚分别是:
1. 生命周期 'a
2. 长度可变 ?Sized
3. 符合 ToOwned trait
*/
pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned,
{
// 借用的数据
Borrowed(&'a B),
// 具有的数据
// 对 B 做了一个强制类型转化,转成 ToOwned trait
// 然后拜访 ToOwned trait 内部的 Owned 类型
Owned(<B as ToOwned>::Owned),
}
意义
Cow(Clone-on-Write)在回来数据的时候,供给了一种可能:
- 要么回来一个借用的数据(只读)
- 要么回来一个具有一切权的数据(可写)
Cow 泛型束缚参数
-
对于具有一切权的数据 B ,第一个是生命周期束缚。
a. 这儿 B 的生命周期是 ‘a,所以 B 需求满意 ‘a,用 B: ‘a 来标明。
b.当 Cow 内部的类型 B 生命周期为 ‘a 时,Cow 自己的生命周期也是 ‘a。
-
B 还有两个束缚:?Sized 和 “where B: ToOwned”
a. ?Sized 是一种特殊的束缚写法,? 代表能够放松问号之后的束缚。
b. 因为 Rust 默许的泛型参数都需求是 Sized,也便是固定巨细的类型,所以这儿 ?Sized 代表用可变巨细的类型
c. ToOwned 是一个 trait,它能够把借用的数据克隆出一个具有一切权的数据
泛型束缚的方式
在表述泛型参数的束缚时,Rust 答应两种方式
- 一种类似函数参数的类型声明,用 “:” 来标明束缚,多个束缚之间用 + 来标明;
- 另一种是运用 where 子句,在界说的结束来标明参数的束缚
- 两种办法都能够,且能够共存
泛型函数
-
在声明一个函数的时候,我们能够不指定具体的参数或回来值的类型,而是由泛型参数来替代
-
对于泛型函数,Rust 会进行单态化(Monomorphization)处理,也便是在编译时,把一切用到的泛型函数的泛型参数展开,生成若干个函数
a. 单态化的优点是,泛型函数的调用是静态分派
b. 编译速度很慢,一个泛型函数,编译器需求找到一切用到的不同类型,一个个编译
小结
好用链接
- 鸭子类型 概念
- 参数多态 概念
- 特设多态 概念
- 子类型多态
- Rust 原生类型
- Iterator trait
- 内存分配 Global
- Rust 默许的大局分配器
- ToOwned trait
- 单态化 概念
- 里氏替换准则
- 各个言语完成和处理泛型
精选问答
- 下面这段代码为什么不能编译经过?你能够修正它使其正常作业么?
use std::io::{BufWriter, Write};
use std::net::TcpStream;
#[derive(Debug)]
struct MyWriter<W> {
writer: W,
}
impl<W: Write> MyWriter<W> {
pub fn new(addr: &str) -> Self {
let stream = TcpStream::connect("127.0.0.1:8080").unwrap();
Self {
writer: BufWriter::new(stream),
}
}
pub fn write(&mut self, buf: &str) -> std::io::Result<()> {
self.writer.write_all(buf.as_bytes())
}
}
fn main() {
let writer = MyWriter::new("127.0.0.1:8080");
writer.write("hello world!");
}
代码报错的主要原因是
- 完成 new 办法时,对泛型的束缚要求要满意 W: Write,而 new 的声明回来值是 Self,也便是说 self.wirter 有必要是 W: Write 类型(泛型)
- 但实际回来值是一个确认的类型 BufWriter<TcpStream>,这不满意要求
修正办法有这么几个思路
- 修正 new 办法的回来值
impl<W: Write> MyWriter<W> {
pub fn new(addr: &str) -> MyWriter<BufWriter<TcpStream>> {
let stream = TcpStream::connect(addr).unwrap();
MyWriter {
writer: BufWriter::new(stream),
}
}
}
fn main() {
let mut writer = MyWriter::<BufWriter<TcpStream>>::new("127.0.0.1:8080");
writer.write("hello world!");
}
- 对确认的类型 MyWriter<BufWriter>完成 new 办法
impl MyWriter<BufWriter<TcpStream>> {
pub fn new(addr: &str) -> Self {
let stream = TcpStream::connect(addr).unwrap();
Self {
writer: BufWriter::new(stream),
}
}
}
fn main() {
let mut writer = MyWriter::new("127.0.0.1:8080");
writer.write("hello world!");
}
- 修正 new 办法的完成,运用依靠注入
impl<W: Write> MyWriter<W> {
pub fn new(writer: W) -> Self {
Self {
writer,
}
}
}
fn main() {
let stream = TcpStream::connect("127.0.0.1:8080").unwrap();
let mut writer = MyWriter::new(BufWriter::new(stream));
writer.write("hello world!");
}