rust基本组成
编译器:Rust是一门静态编译型语言。Rust官方的编译器叫rustc,负责将
Rust源代码编译为可执行文件或其他库文件(.a、.so、.lib、.dll等)。特点是跨平台的,后端用了LLVM。
核心库和标准库
Rust语言的语法由核心库和标准库共同提供。其中Rust核心库是标
准库的基础。可以通过在模块顶部引入#![no_std]来使用核心库。核心库和标准库的功能有一些重复。标准库比如有IO操作系统交互。
包管理器:把按一定规则组织的多个rs文件编译后就得到一个包(crate)。包是Rust代码的基本编译单元,也是程序员之间共享代码的基本单元。
Rust提供了非常方便的包管理器Cargo,类似于Python中的pip。
但Cargo不仅局限于包管理,它还为Rust生态系统提供了标准的工作流。Cargo 能够管理整个工作流程,从创建项目、运行单元测试和基准测试,到构建发布链接库,再到运行可执行文件,等等。使用cargo new命令默认可以创建一个用于编写可执行二进制文件的项目。通过给cargo new命令添加–lib参数,则可以创建用于编写库的项目。此外,通过cargo build和cargo run命令可以方便地对项目进行编译和运行。
语句和表达式
Rust 中的语法可以分成两大类:语句(Statement)和表达式
(Expression)。语句是指要执行的一些操作和产生副作用的表达式。
表达式主要用于计算求值。
语句又分为两种:声明语句( Declaration statement)和表达式语
句( Expression statement)。
· 声明语句,用于声明各种语言项(Item),包括声明变量、静态
变量、常量、结构体、函数等,以及通过extern和use关键字引入包和模
块等。
· 表达式语句,特指以分号结尾的表达式。此类表达式求值结果将
会被舍弃,并总是返回单元类型()。
这部分再说。
变量和绑定
通过let关键字来创建变量,这是Rust语言从函数式语言中借鉴的语
法形式。let创建的变量一般称为绑定(Binding),它表明了标识符
(Identifier)和值(Value)之间建立的一种关联关系。
Rust 中的表达式一般可以分为位置表达式( Place Expression)和
值表达式( Value Expression)。在其他语言中,一般叫作左值
(LValue)和右值(RValue)。
也就是说,左边是代表内存位置的,是变量,右边是要么是字面量,要么是表达式求值过程中创建的临时值。
这一点优点类似于const关键字,但是也不太一样,const是只读,不允许修改变量,但不是没有写权限。
所有权与引用
当位置表达式出现在值上下文中时,该位置表达式将会把内存地址转移给另外一个位置表达式,这其实是所有权的转移。(注意,字面量不能作为左值。但是变量可以作为右值)
在语义上,每个变量绑定实际上都拥有该存储单元的所有权,这种转移内存地址的行为就是所有权(OwnerShip)的转移,在 Rust 中称为移(Move)语义,那种不转移的情况实际上是一种复制(Copy)语义。Rust没有GC,所以完全依靠所有权来进行内存管理。在日常开发中,有时候并不需要转移所有权。Rust提供引用操作符(&),可以直接获取表达式的存储单元地址,即内存位置。可以通过该内存位置对存储进行读取。
let p=“hello”;
let other=p; 将p的内存地址转移给other;
let a=[1,2,3];
let b=&a; 定义了固定长度数组a,并且使用引用操作符&取得a的内存地址,赋值给 b。这种方式不会引起所有权的转移,因为使用引用操作符已经将赋值表达式右侧变成了位置上下文,它只是共享内存地址。
函数和闭包
函数是通过关键字fn定义的。其函数签名pub fn fizz_buzz(num:i32)->String清晰地反映了函数的类型约定:传入i32类型,返回String类型。
rust是由{}来声明作用域。同一作用域,初始化两次i,i的值为第二次。不同作用域的变量有不同的生命周期,独立的。
函数指针
函数自身就可以作为函数的参数和返回值使用。直接使用函数的名字作为函数指针。
关于CTEE机制和闭包先不讨论。防止和函数搞混淆。
流程控制
表达式一定会有值,所以if表达式的分支必须返回同一个类型的值
才可以。这也是Rust没有三元操作符?:的原因。if表达式的求值规则
和块表达式一致
Rust中包括三种循环表达式:while、loop和for…in表达式,其用法
和其他编程语言相应的表达式基本类似。match表达式与模式匹配,有点类似其他编程语言中的switch或case语句。match表达式必须穷尽每一种可能,所以一般情况下,会使用通配符_来处理剩余的情况
基本数据类型
布尔类型
let x=true;
let y:bool=false; 这两种声明是一样的; x as i32把布尔类型转换为整型1。
基本数字类型大致可以分为三类:固定大小的类型、动态大小的类型和浮点数。固定大小的包括无符号有符号。
在Rust中,使用单引号来定义字符(Char)类型。字符类型代表的是一个Unicode标量值,每个字符占4个字节。可以使用as操作符将字符转为数字类型
常用复合数据类型:
元组tuple:可以存储不同类型数据
结构体,枚举体。
常用集合数据类型:
Vec数组,deque双端队列。linkedlist链表,hashmap, btreemap,set等
这些都和C++l类似。
智能指针呢:Box<T>是指向类型为T的堆内存分配值的智能指针。当Box<T>超出作用域范围时,将调用其析构函数,销毁内部对象,并自动释放堆中的内存。可以通过解引用操作符来获取Box<T>中的T。
泛型和trait是Rust类型系统中最重要的两个概念
Rust 标准库中定义了很多泛型类型,包括 Option<T>、Vec<T>、HashMap<K,V>以及Box<T>等。
代码第3行到第5行使用trait关键字定义了一个Fly trait。在Rust中,trait是唯一的接口抽象方式。使用trait可以让不同的类型实现同一种行为,也可以为类型添加新的行为
Duck和Pig根据自身的类型针对同一个接口进行Fly,实现了不同的行为。Rust中并没有传统面向对象语言中的继承的概念。Rust通过trait将类型和行为明确地进行了区分,充分贯彻了组合优于继承和面向接口编程的编程思想。
具体不细说
错误处理
Rust 中的错误处理是通过返回 Result<T,E>类型的方式进行的。Result<T,E>类型是Option<T>类型的升级版本。
用于构建健壮的程序,具体也不细说了。