首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >系统编程语言Rust特点介绍(1)

系统编程语言Rust特点介绍(1)

原创
作者头像
glinuxer
发布2019-09-28 14:52:47
1.5K0
发布2019-09-28 14:52:47
举报
文章被收录于专栏:专注网络研发专注网络研发

最近在学习Rust语言,感觉这门语言有点意思,因此写一篇文章分享。我不会去介绍Rust的基本语法,什么变量声明,if..else..,循环等等。这些东西,文档介绍的很清楚,何必多此一举。本文主要介绍Rust这门语言的特点,和其它语言的对比。

虽然学习时间不长,但已经体会到Rust语言的特点就是极致的追求“安全”,追求代码的稳健。为了达到这个目标,Rust增加了不少编码“限制”(或者称之为规则),让码农们要循规蹈矩的写代码,从而实现“编译即无bug”的目标。(前提条件,编码的逻辑必须正确:D)

在我看来,系统编程语言可以实现对性能要求极高,同时对硬件要求很低的语言,经常用于平台开发。一般来说,就是C和C++。而这两门语言,要写出“安全”的代码,还是有一定门槛的。而Rust就针对“安全”这个方向,做了很多工作,同时保持高性能。

Rust语言的工程管理工具叫做cargo,它负责工程建立,编译,包的依赖等等。

下面开始介绍Rust的一些特点:

一、工程化支持:

按惯例,我们创建一个helloworld工程。

cargo new hellworld

图1. 创建工程
图1. 创建工程

cargo会自动在当前目录创建一个helloword目录,作为项目目录。

图2. 目录描述
图2. 目录描述

ls该目录,可以看到有一个文件Cargo.toml和src目录,前者Cargo.toml为项目描述和管理文件,起到了项目管理和“Makefile”的作用。

图3. toml文件
图3. toml文件

接下来看rust源代码

图4. rust生成代码
图4. rust生成代码

当创建Rust工程时,rust会自动生成main.rs的原文件,恰好是我们需要的打印hello world。接下来看rust的编译和运行。

图5. cargo build
图5. cargo build

执行cargo build进行编译,生成debug版本的可运行程序。如果要生成release版本,只需要加上--release选项。生成的二进制,cargo也会放在指定目录target目录下。

接下来让我们用Rust生成一个库工程 —— 使用--lib参数。

图6. 生成库
图6. 生成库

与bin工程类似,cargo在addlib/src目录下自动生成了一个lib.rs文件。

图7. 库代码
图7. 库代码

文件中的mod tests是Rust对单元测试的支持。这里我们先不介绍,只要了解这段代码是用于单元测试即可。—— 从这里又可以看到Rust的一个好处:D

下面让我们写个简单的add函数,作为addlib的接口。

图8. 单元测试
图8. 单元测试

然后编译和做单元测试如下:

图9. 运行单元测试
图9. 运行单元测试

可以看出,rust对工程化的支持还是很友好的:

1. 免去了编写工程文件的痛苦;

2. 格式化的目录结构

3. 支持单元测试

4. 支持自动生成文档(cargo doc)

二、“强制”的Error Handler

Rust的错误分为两种:Panic和Results。前者表示“永远”不应该发生的事情,后者表示程序逻辑产生的错误。

下面看一个产生panic的情况

图10. error handler示例代码
图10. error handler示例代码

编译运行这个rust程序

图11. error handler运行
图11. error handler运行

可以看到箭头所指的位置,程序直接panic了。这种错误是无法在编译阶段捕捉的。

下面看第二种情况,rust对错误检查的“强制”处理。

图12. 错误检查代码
图12. 错误检查代码

使用cargo编译,会报告三个warning,提示没有检查返回值

图13. 错误检查编译
图13. 错误检查编译

这时,我们要么加上返回值检查,要么使用Rust提供的unwrap方法来消除警告。

图14. 错误检查修复
图14. 错误检查修复

使用match语句检查my_function的返回值,按照Rust的语法,要求必须把所有可能的值都检查到,不然就会报错。可见上面的代码写起来还是有些繁琐的。而用unwrap的方式,就是像Rust承诺,这个函数不会返回出错。那么当my_function返回出错时,会怎么样呢?

图15. 错误检查panic
图15. 错误检查panic

说话不算数,Rust就死给你看:)

三、对库的版本管理

作为从业多年的码农,大家一定会遇到对第三方库的管理和依赖问题。这里Rust的cargo提供了很友好的方式,通过Cargo.toml文件进行第三方库的管理。

图16. Rust第三方库管理
图16. Rust第三方库管理

这个示例要利用rand库生成随机数,其版本为0.4.*版本。使用cargo build进行编译

图17. Rust获取库
图17. Rust获取库

其会自动下载符合定义的库,rand v0.4.6版本。

如果某天要升级到0.5版本,只需要更改toml文件,改为rand = "0.5.*",然后执行cargo update更新库。

图18. Rust更新库
图18. Rust更新库

是不是很方便呢?

四、保证内存安全

绝大部分crash和安全问题都是由于内存问题导致的,比较常见的几种问题:

1. 引用空指针;

2. 引用未初始化指针;

3. 引用释放后的指针;

4. 溢出或越界;

5. Double Free;

Rust通过严格语法检查,所有权系统和生命周期来保证了以上几种情况不会在Rust下发生,或者极容易定位。

看下面的示例代码

图19. Rust内存安全代码
图19. Rust内存安全代码

这里有4个常见的内存错误,如代码中的注释。使用cargo build编译,看看rust是如何阻止这些错误的。

图20. Rust内存安全代码报错
图20. Rust内存安全代码报错

这里一共出现了3个编译错误,分别防止了1)未初始化的引用;2)引用已经销毁的变量;3)避免Double Free。Rust中的Box::new是用来从堆上申请内存的,类似于C/C++中的指针,当超过其生命周期后,会自动释放内存。但是当将一个指针的值赋给另外一个指针,即将内存的“所有权”交给了第二个指针。第一个指针就不能再被引用。

代码中一共有4个错误,cargo阻止了三个,剩下的overflow的问题怎么办呢?让我们先把上面的3个问题纠正,让cargo编译出可执行程序并运行。

图21. Rust内存安全之越界
图21. Rust内存安全之越界

在运行到overflow的代码时,直接崩溃,并明确的告知这里出现了越界访问。这样的“死亡”方式,要比踩踏了其他内存导致程序不知道挂在哪里的方式,要好上很多。我相信,大家都经历过修复内存越界的Bug,查起来可不是那么简单。与其带着“炸弹”运行,不如直接在现场挂掉暴露问题的好。

本想一篇文章介绍完Rust所有权系统,包含Ownership,Borrowing,和Lifetimes。这三方面保证Rust的内存安全,也就是保证构成健壮的程序。下一篇文章,将介绍Rust所有权系统

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
项目管理
CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档