聊聊Rust中的move语义

2022-08-17 12:55:47 浏览数 (1)

概述

  • 最近疫情期间在看开发效率和zero overhead两者都比较折中的开发语言工具,目前主流的编程语言,c就不用说了,语法简单,借助于开源的开发库构建负责的大型项目,自由度非常高,但是带来的负担就是必须手动管理好你申请的每一块的heap上的内存,一旦这块做稳妥了,基于c的二进制的binary程序非常稳定(比如业界的redisnginx),在基于c的代码大型项目至少70%的问题都可以归咎于内存的问题。go是一个开发webHigh concurrency的网络服务和工具研发的最佳选择,开发效率非常高,标准库和开源第三方库也非常多,但是go自身的gc对于低延迟服务还是存在SWT的问题,业界基于go的项目有k8s/docker,这些都是云原生领域的基础。最后我们在看看rust语言,语言设计的核心是zero overhead,完美和底层的其他的语言进行交互,借助于变量的ownershipcomplie期间来一套规则检查代码和代码执行期间的变量释放,无需手动的管理内存问题,同时又提高了开发效率,但是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上的资源给释放

0 人点赞