概述
- 最近疫情期间在看开发效率和
zero overhead
两者都比较折中的开发语言工具,目前主流的编程语言,c
就不用说了,语法简单,借助于开源的开发库构建负责的大型项目,自由度非常高,但是带来的负担就是必须手动管理好你申请的每一块的heap
上的内存,一旦这块做稳妥了,基于c
的二进制的binary
程序非常稳定(比如业界的redis
和nginx
),在基于c的代码大型项目至少70%
的问题都可以归咎于内存的问题。go
是一个开发web
和High concurrency
的网络服务和工具研发的最佳选择,开发效率非常高,标准库和开源第三方库也非常多,但是go
自身的gc
对于低延迟服务还是存在SWT
的问题,业界基于go的项目有k8s/docker
,这些都是云原生领域的基础。最后我们在看看rust
语言,语言设计的核心是zero overhead
,完美和底层的其他的语言进行交互,借助于变量的ownership
和complie
期间来一套规则检查代码和代码执行期间的变量释放,无需手动的管理内存问题,同时又提高了开发效率,但是rust
的学习曲线确实比较高。
move语义
move
语义是把一个变量的所有权从一个空间移动到另外一个空间。Rust中的move
语义,比如针对一个对象struct T
和一个函数change(t : T)
,可以传递self
到该函数参数,这时候 struct T
的所有权就转移到了change
函数栈内。接下来看看如下的代码实例
代码语言:javascript
复制// 定义公开的结构体
pub struct T {
// id 类型是u8
id: u8,
// uuid 是字符串类型
uuid: String,
}
// 公开方法
pub fn print_t(t1: T) {
println!("id={},uuid={}", t1.id, t1.uuid);
}
fn main() {
// 栈上定义变量t1,uuid 是从data段memcpy到堆上的
let t1 = T {
id: 100,
// test-uuid 实在程序的Data段内,拷贝到heap上
uuid: "demo".to_string(),
};
// t1进入的print_t1函数内后,把所有权也全部转发给print_t函数内
print_t(t1);
// 执行完毕,释放所有的资源,这里rust编译器可插入很多内部资源释放的方法
}
/***rust string的实现**********/
// 底层是一个动态的字节切片
pub struct String {
vec: Vec<u8>,
}
// Vec的切片的定义
pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
buf: RawVec<T, A>,
len: usize,
}
// RawVec切片定义
pub(crate) struct RawVec<T, A: Allocator = Global> {
ptr: Unique<T>,
cap: usize,
alloc: A,
}
- rust中的
String
和redis的字符串实现思想一直,都是一个指针指向data_ptr/cap/len
.这个程序编译完成以后会在Data
段内存储demo
字符串,调用to_string
在底层可以理解为malloc和memcpy
这2个动作,把数据拷贝到heap
上
- 当调用
print_t
函数时候,rust把t1这个变量的所有权转让给print_t
内,原来main stack
中的t1
被标记为不可访问,但是t1
执行的数据还是原来的位置。print_t stack
拥有t1
的所有权,等程序执行完毕以后,rust编译器应该会插入对应的资源释放的代码,把heap
上的资源给释放