Rust之抽空学习系列(二)------ 编程通用概念(上)
Rust 作为一门强类型的静态类型语言,会有哪些与生俱来的天赋呢?
1、静态类型语言 vs 动态类型语言
特性 | 静态 | 动态 |
---|---|---|
类型检查 | 编译时 | 运行时 |
错误检测 | 执行前 | 执行期间 |
代码灵活性 | 低 | 高 |
性能 | 通常更快 | 可能会更慢 |
代表 | Rust、Java、C# | Python、JavaScript |
静态主要对应编译时 ,而动态对应运行时
下面这段Rust代码在显式声明变量a的类型为i32
(当然根据初始值Rust也能够推导出来),编译期这个类型被确定下来
此时,你可以修改这个变量的值,至于类型嘛,已经板上钉钉了(Rust是静态类型)
rust
fn main() {
let a: i32 = 10; // 显式指定类型为i32
println!("a: {}", a);
}
但是像Python这种动态类型就比较好说话了,随便写,换个类型都不是事
py
x = 10 # 并未声明类型
print(x)
x = 'hello' # 重新赋值,换成字符串类型
print(x)
2、强类型 vs 弱类型
特性 | 强类型 | 弱类型 |
---|---|---|
数据类型声明 | 显式、隐式 | 隐式 |
类型约束 | 严格 | 宽松 |
类型转换 | 需要显式进行 | 隐式进行 |
隐式转换 | 少见/罕见 | 常见 |
错误检查 | 多在编译时 | 多在运行时 |
类型安全性 | 高;较少出现意外行为 | 低;更容易出现不可预期的结果 |
代表 | Rust、Java、Python | JavaScript、PHP |
像Rust这种强类型语言是比较严格的,通常是不会允许有隐式转换的,规规矩矩,呆板有呆板的好处
下面这段代码,x和y显然是两种不同类型的值,那么这个加法显然不太合理,Rust看到这种就是手起刀落,提示这是不支持的操作,开发者此时就被迫思考,想清楚自己要做什么,减少bug产出
而像JavaScript这种弱类型的语言,用过的都知道,写起来一时爽,自由度挺高的,找bug嘛,就比较麻烦了,尤其像那种不经意就给整到隐式转换里的
像下面这段,如果你是想10 + 20结果是30的,就错了,JS帮你全转成字符串了,你自己如果不检查,代码自身又检测不出这种问题,很有可能就被藏起来
3、编译型 vs 解释型
3.1、编译型
编译型语言通常是开发者编写完代码,然后由编译器 进行编译,生成对应的可执行文件 (包含机器码内容),并且最终将这个可执行文件分发给用户,用户直接拿来就可以运行
3.2、解释型
解释型语言则是开发者编写完源代码,然后将代码的副本 给用户,用户的机器上安装上解释器 ,然后解释器将代码逐行解释执行
3.3、对比
特性 | 编译型语言 | 解释型语言 |
---|---|---|
编译过程 | 需要编译步骤来生成可执行文件 | 无需编译,代码直接由解释器执行 |
编译时间 | 编译大型项目可能耗时较多 | 即时反馈,无需编译 |
依赖性 | 只需二进制文件和必要的库即可执行 | 需要安装解释器才能执行代码 |
可移植性 | 需要为不同平台重新编译 | 任何有解释器的平台都可以运行 |
执行速度 | 通常更快 | 通常较慢 |
内存使用 | 通常更节省内存,编译时会进行优化 | 由于解释开销,通常会占用更多内存 |
修改和测试 | 修改后需要重新编译,迭代较慢 | 修改后可以直接测试,无需重新编译,迭代较快 |
代表 | C、C++、Rust、Go | Python、JavaScript、Ruby |
中间方法 :
类似Java和C#
结合了编译型语言 和解释型语言 各自的特点进行融合
①编译过程 :编译成中间产物,没有直接生成机器码 ,生成了与平台无关的中间语言 ,作为程序集 分发给使用者
②执行过程 :通过运行时进行程序集加载,由JIT编译为本地机器码 ,通过优化适应硬件环境 ,一方面具有较高执行效率 ,另一方面又具有跨平台的灵活性
4、栈内存 vs 堆内存
内存中的数据 主要存储在堆 和栈这两大结构上
4.1、栈(Stack)
栈按接收数据的顺序存储 并且以与之相反的顺序移除 ,适合存储已知固定大小的数据 ,遵循后进先出(LIFO)原则
通常由系统自动分配和释放 ,访问速度快,但是大小比较有限
4.2、堆(Heap)
堆允许存储在编译期未知大小的数据 ,访问速度较慢(访问堆内存这部分)
通常需要开发者自己控制分配与释放,或者GC的支持,结构无序,管理难度较大
实际的使用中通常配合栈内部的指针变量 进行访问
4.3、堆管理问题
- 双重释放
- 内存泄漏
- ...
Rust 中采取所有权机制在不使用GC的情况下依然能够很好地管理堆内存的使用,是其一大特色