专栏首页专注网络研发系统编程语言Rust特点介绍(1)
原创

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

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

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

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

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

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

一、工程化支持:

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

cargo new hellworld

图1. 创建工程

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

图2. 目录描述

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

图3. toml文件

接下来看rust源代码

图4. rust生成代码

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

图5. cargo build

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

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

图6. 生成库

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

图7. 库代码

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

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

图8. 单元测试

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

图9. 运行单元测试

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

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

2. 格式化的目录结构

3. 支持单元测试

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

二、“强制”的Error Handler

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

下面看一个产生panic的情况

图10. error handler示例代码

编译运行这个rust程序

图11. error handler运行

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

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

图12. 错误检查代码

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

图13. 错误检查编译

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

图14. 错误检查修复

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

图15. 错误检查panic

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

三、对库的版本管理

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

图16. Rust第三方库管理

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

图17. Rust获取库

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

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

图18. Rust更新库

是不是很方便呢?

四、保证内存安全

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

1. 引用空指针;

2. 引用未初始化指针;

3. 引用释放后的指针;

4. 溢出或越界;

5. Double Free;

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

看下面的示例代码

图19. Rust内存安全代码

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

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

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

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

图21. Rust内存安全之越界

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

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

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

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

    最近在学习Rust语言,感觉这门语言有点意思,因此写一篇文章分享。我不会去介绍Rust的基本语法,什么变量声明,if..else..,循环等等。这些东西,文档介...

    glinuxer
  • DPDK之KNI原理

    DPDK是一个优秀的收发包kit,但它本身并不提供用户态协议栈,因此由将数据报文注入内核协议栈的需求,也就是KNI(Kernel NIC Interface)。...

    glinuxer
  • DPDK之PMD原理

    PMD是Poll Mode Driver的缩写,即基于用户态的轮询机制的驱动。本文将介绍PMD的基本原理。

    glinuxer
  • comsol快速入门教程

    我自己参照官网的教程,写了个比较通俗易懂的入门教程,字多图多慎看(大三的时候写的)。

    desperate633
  • 数据库与图片完美解决方案

    目录 1. 背景 2. 解决思路 3. 解决方案 4. plugin 的开发与使用 5. 在事务中使用该插件 6. 通过触发器调用图片处理函数 1. 背景 我以...

    netkiller old
  • 数据库与图片完美解决方案

    数据库与图片完美解决方案 电商商品图品与数据库脏数据完美解决方案 摘要 你是是不是在开发中常常遇到,删除了数据库记录后,发现该记录对应的图片没有删除,或者删除了...

    netkiller old
  • 数据库与图片完美解决方案

    数据库与图片完美解决方案 电商商品图品与数据库脏数据完美解决方案 摘要 你是是不是在开发中常常遇到,删除了数据库记录后,发现该记录对应的图片没有删除,或者删除了...

    netkiller old
  • 高质量编码-GIS搜索框

    GIS中经常遇见通过搜索框搜索要素,同时地图同步高亮显示的需求。本文介绍一种实现方式。

    MiaoGIS
  • 【Rust日报】 2019-12-13 async-std v1.3.0 出世了!

    MikeLoveRust
  • Day and Night Image data Standardization

    小飞侠xp

扫码关注云+社区

领取腾讯云代金券