专栏首页专注网络研发系统编程语言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所有权系统

本文分享自微信公众号 - LinuxerPub(LinuxerPub),作者:glinuxer

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

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

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

    glinuxer
  • VSZ与RSS

    使用ps命令查看进程的内存使用情况时,有3列输出,分别是%MEM、VSZ和RSS,其中VSZ全称为Virtual Memory Size,RSS...

    glinuxer
  • 细说TCP的MSS选项(1)

    前几天,我厂剑英和晓培同学在定位一个TCP通信失败问题时,发现原因是客户端发送的TCP数据过长(1460字节),导致数据包无法成功发送到服务端。...

    glinuxer
  • 【Rust日报】 2019-05-16:在Rust中创建C/C++ API

    这个清单如果继续写下去会很长,Rust已经在众多领域陆续开花了。Rust社区感谢有你!

    MikeLoveRust
  • Rust FFI 编程 - 手动绑定 C 库入门 01

    本篇为一个新的章节《手动绑定 C 库入门》的第一篇。从这个章节开始,我们将会进行使用 Rust 对 C 库进行封装的实践。

    MikeLoveRust
  • 多云一定会起到容灾作用吗?

    容灾这个事情,跟多不多云没有任何关系,单个云厂商的公有云里照样可以保障容灾,复杂度还要比多云低一些,也更具备可操作性。

    赵成
  • Golang 需要避免踩的 50 个坑(三)

    Go 是一门简单有趣的编程语言,与其他语言一样,在使用时不免会遇到很多坑,不过它们大多不是 Go 本身的设计缺陷。如果你刚从其他语言转到 Go,那这篇文章里的坑...

    aoho求索
  • 数据类增加nonNull字段反序列化的坑

    那么后来,万恶的产品经理该需求啦,说这个 Person 里面还需要有一个公司,也就是我们要改成:

    bennyhuo
  • Java设计RestfulApi接口,实现统一格式返回

    sunny1009
  • 3分钟懂线性回归预测算法瞅一眼,懂个概念也值得

    线性回归(linear-regression)预测算法C++实现 上一期,和大家分享了K-means聚类算法的基本概念和实现要点(漏了的同学欢迎加公众号回顾),...

    架构师之路

扫码关注云+社区

领取腾讯云代金券