rust语言浅谈
Rust是由Mozilla主导开发的通用、编译型编程语言。设计准则为“安全、并发、实用”,支持函数式、并发式、过程式以及面向对象的编程风格。
Rust语言近年来非常流行,我也是Rust编程语言的爱好者,这篇文章就简单的谈一谈Rust语言的各个方面。
安全性
语言的安全性非常重要,很多的软件bug都是由于语言安全性问题导致的。
类型安全
Rust是一种强类型,而且类型安全的编程语言。并不是所有的强类型语言都能保证类型安全,例如C/C++的void*可以随意改变类型,Java的泛型会擦除类型。
内存安全
内存管理是一大难题,除了rust之外,现代的编程语言可以分为两类。
手动管理内存的语言,如C/C++。
使用垃圾回收算法自动管理内存的语言,如Java、C#、Go
一些语言中具有垃圾回收机制,在程序运行时不断地寻找不再使用的内存;
在另一些语言中,程序员必须亲自分配和释放内存。
Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。在运行时,所有权系统的任何功能都不会减慢程序。
rust的所有权规则
首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则:
- Rust 中的每一个值都有一个被称为其 所有者(owner)的变量。
- 值在任一时刻有且只有一个所有者。
- 当所有者(变量)离开作用域,这个值将被丢弃
运行效率
标准Rust性能与标准C++性能不相上下,某些场景下效率甚至高于C++。 由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务。
其他特性
rust还有一些特性来帮助开发者提高编程效率。
宏
从根本上来说,宏是一种为写其他代码而写代码的方式,例如我们经常使用的 println!
宏和 vec!
宏。所有的这些宏以 展开 的方式来生成比你所手写出的更多的代码。Rust 的宏不是简单的文字查找与替换,宏展开生成的代码也会进行编译检查。
高级的枚举
在其他语言中,枚举一般类似于常量来使用,而rust的枚举是可以包含其他值的,从而可以实现更加高级的功能。
1 | //例如常见的Option枚举,表示可能为空的值,类似于Java的Optional<T> |
错误处理
rust使用Result<T,E>
枚举包裹一个值,如果没有错误,就可以通过匹配得到Ok(T),如果有错误,则就是Err(err)。rust建议所有的Result都必须被处理,否则编译器就会发出警告。
crates包
包这个概念是node.js
弄出来的,可以很方便的进行引用,rust也有依赖包功能。
并发
在web编程领域,服务器等待io的时间通常远多于CPU计算的时间,如果采用同步流程,程序在遇到网络或者文件读写的时候,就只会原地等待读写完成。node.js
是推进异步编程的重大贡献者,node.js
基于事件循环进行程序调度,当遇到io阻塞时,就会先执行队列中其他代码,从而提高CPU的利用率。
Go语言的协程也有类似的原理,就不说了。
一般的异步调度程序会轮询队列里面的状态信息,如果发现状态改变,再调度过来执行后续逻辑。
而rust的异步模型基于Future,它是惰性的,不会不停的查询状态信息,而是提供一个回调函数。io完成后,再调用回调函数,通知Future可以来查询状态了,它才会来查询状态信息,做出调度。
rust的并发运算除了Future异步模型外,也有原生线程,给用户多种选择。不像go语言,go语言只给用户提供了协程,而没有原生的线程,所以go语言一般都用于网络编程。
有些程序涉及到大量的运算,没有io或者很少io,这种情况下用多线程计算会更快,因为Future的异步调度也要一些开销。总结如下:
io密集型的程序,适合使用Future
CPU运算密集的程序,适合使用多线程
FFI
FFI(Foreign Function Interface)是用来与其它语言交互的接口。现实中很多程序是由不同编程语言写的,必然会涉及到跨语言调用,比如 A 语言写的函数如果想在 B 语言里面调用,这时一般有两种解决方案:
后者直接将其它语言的接口内嵌到本语言中,调用效率比前者高。当前的系统编程领域大部分被 C/C++ 占领,而 Rust 定位为系统编程语言,少不了与现有的 C/C++ 代码交互,另外为了给那些”慢”脚本语言调用,Rust 必然得对 FFI 有完善的支持。