在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、关于内存管理 1、rust加入了生命周期和所有权的特性,实现内存自动回收,避免内存泄漏和野指针的问题。 例如:,局部变量离开作用域后Rust会连同变量绑定的内存,不管是否为常量字符串,连同所有者变量一起被销毁释放。所以上面的例子,a销毁后再次访问a就会提示无法找到变量a的错误。 这些所有的一切都是在编译过程中完成的。 2、Rust没有null,取而代之的是None和Option<T>,且Rust并不会像其他语言一样可以为变量默认初始化值,Rust明确规定变量的初始值必须由程序员自己决定。 例如:如果a不初始化,则会产生如下错误: 3、移动语义的概念 Rust的移动语义和C++11标准中的移动语义类似,都是可以解决内存多次释放造成系统崩溃问题。但是Rust的概念稍微有些特殊,来个例子 编译之后会得到如下的错误:
从编译信息可以看出,编译器会做尽可能多的检查,争取在编译期间就发现问题,且编译信息友好,有的问题直接就给你提示,告诉你怎么修改会让程序顺利编译通过。(缺点就是编译时间太长~~~) 先看红色的编译提示 第三个 错误的意思是在println中访问了被moved的变量a 在Rust中,有个机制叫做“转移move所有权”,意思是,可以把资源的所有权(ownership)从一个绑定a转移(move)成另一个绑定b,被move的变量a不可以继续被使用。 还有一个问题,move后,如果变量a和变量b离开作用域,所对应的内存会不会造成“C++经常遇到的2次释放”的问题?不会的,只有资源的所有者销毁后才释放内存,而无论这个资源是否被多次move,同一时刻只有一个owner(有点类似C++11中的 unique_ptr)所以该资源的内存也只会被释放一次。通过这个机制,就保证了内存安全。
我们再看 第一个 的警告提示,在Rust中,如果定义了一个未被使用的变量,是需要给用户提示警告信息,并告诉用户如果想消除此警告信息,例如图中所示,加个”_”即可,但是在实际编程中,未被使用的变量是不会让其存在的。 再看 第二个错误 在Rust中String类型是没有实现Copy特性的,如果将上面的代码中的a改成i32类型,就可以编译通过,因为i32实现了Copy特性,在move时会拷贝资源到新的内存区域,move前后的a和b对应资源内存的地址不同。(Rust中,基本数据类型均实现了Copy特性)
二、关于Future 1、什么是Future,可以理解成一种不会立即执行的古怪函数,他会在未来被执行(future名字的由来?)我们可以利用Future,将逻辑异步转成同步的代码,通过and_then将各个future串联起来,将来依次执行,所以,我们在多线程开发过程中,只需要关心future怎么写,怎么传递。缺点是代码可读性不高,通篇都是and_then,脑袋大。 在future的串联过程中,把一个future的返回值传给下一个future的部分有点棘手,在Rust中,我们使用闭包参数来捕获(Rust的闭包有点类似于C++11标准中的lambda表达式)。
2、麻烦的Error,把future连接起来并不困难,但是他们的错误类型必须都要匹配上去才行,即链式futures的错误类型必须要统一,否则编译不过!这也是我开发过程中遇到最多的编译错误问题。这就引出了From的概念 单独举个小例子: 假设我们已经定义了两个错误类型ErrorA和ErrorB fn fut_error_a() -> impl Future<Item = (), Error = ErrorA> { err(ErrorA {}) } fn fut_error_b() -> impl Future<Item = (), Error = ErrorB> { err(ErrorB {}) } 然后把他俩串起来 let future = fut_error_a().and_then(|_| fut_error_b()); 编译之后出现错误 | let future = fut_error_a().and_then(|_| fut_error_b()); | ^^^^^^^^ expected struct `errors::ErrorB`, found struct `errors::ErrorA` | = note: expected type `errors::ErrorB` found type `errors::ErrorA` 我们在本该有ErrorB的地方得到一个ErrorA, 我们可以利用std::convert::From trait,使用From,可以告诉Rust怎么全自动从元类型转成目标类型 impl From<ErrorB> for ErrorA { fn from(e: ErrorB) -> ErrorA { ErrorA::default() } } impl From<ErrorA> for ErrorB { fn from(e: ErrorA) -> ErrorB { ErrorB::default() } }
let future = fut_error_a().map_err(|e| ErrorB::from(e)).and_then(|_| fut_error_b()); 这样的话,错误类型一致,编译错误取消。 在开发中,最好单独有个error.rs的文件,专门去做错误类型转换的功能。 三、项目构建 为了解决C/C++项目的管理问题 ,开发出了cmake 、qmake等项目管理工具,但结果并不如人意, C/C++er经常会陷入在掌握语言本身的同时,还要掌握复杂的构建工具语法的窘境。作为rust的代码组织管理工具,cargo提供了一系列的工具,从项目的建立、构建到测试、运行直至部署,为rust 项目的管理提供尽可能完整的手段。 其中说一下最重要的cargo.toml文件。
[package]: 描述了软件开发者对本项目的各种元数据描述信息,项目名称、版本、作者等等 [dependencies]:描述该项目的各种依赖项
四、其它 代码里禁止出现expect(),unwrap()函数。取而代之用默认值,或者修改类型(不用Option,Result) 总之:一句话总结Rust和C++的区别,我的想法就是: rust:编译时想撞墙。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论