2KB项目,专业的源码交易网站 帮助 收藏 每日签到

Rust 语言如何帮助你防止 bug

  • 时间:2019-01-23 18:26 编辑:2KB 来源:2KB.COM 阅读:542
  • 扫一扫,手机访问
  • 分享
摘要:
Rust 英文原文:How Rust Helps You Prevent Bugs

引言

如果你曾经编写过任何规模大小的程序,你可能会遇到各种错误。你在编码时产生的微小的错误会导致你的程序执行失败。程序越复杂,发生错误的概率越高!

为了修复和防止错误,有很多方法可供程序员使用。其中一个是在运行程序之前确定程序的正确性:静态类型。这种技术是设计编程语言的一部分,并且可以防止简单的错误,例如尝试使用字符串作为整数,或者比较类型不同的对象,例如 Car 和 Book

我的个人观点是,编程语言及其实现应该尽可能地捕获程序员所犯的错误,从而使得他们能构建更好更安全的软件。虽然静态类型使得语言更加复杂和难以学习,但它为程序员提供了一个安全的机制,我相信这是非常值得的。

Rust 语言实现了这样的静态类型系统,并提供了捕获错误的新方法,这在其他语言中运行时会导致崩溃。在这篇文章中,我将会讲解其中一些方法。

Null 返回

子程序由于遇到某种边界情况而无法返回结果并不罕见。想想一个例子:在数组中查找并不包含某项元素的索引,从空堆栈中弹出元素或在很小的数组上的通过索引访问元素。这些处理方式在不同语言之间差别很大。最常见的处理方式似乎是抛出异常或返回 null(或-1)。

如果你忘记检查 -1 或 null 或捕获异常,你的程序将会崩溃。然而,Rust 有一个确保在编译时捕获和处理错误的策略。

Option 类型

使用Rust的标准库Option来处理函数边界情况。这是一个枚举类型(如果你熟悉C语言的话,有点像一个联合体)包含有两个可能的值。这是它的声明:

enum Option<T> {
  None,
  Some(T),
}

例如,Vec::pop 方法,从堆栈向量中弹出最后一个元素,当堆栈向量中至少有一个元素时返回 Some 和元素,如果堆栈向量为空,则返回 None 。

现在,获取一个 Option 的值需要一个match结构。我们不能只是声明一个值已经被返回,并且像返回一个指针的语言一样使用它。那很好!程序员被迫考虑如何处理返回 None 的情况。如果在另一种语言中类似的代码会导致运行时错误,而在 Rust 中,将会阻止程序被编译:

let mut numbers = vec![21];
let maybe_number = numbers.pop(); // Option<i32>
println!("{}", maybe_number * 2); //  编译错误!

这个出现这个错误报告: error[E0369]: binary operation * cannot be applied to type std::option::Option<{integer}> 

必须使用 match 来判断是否有返回结果:

let mut numbers = vec![21];
let maybe_number = numbers.pop();
if let Some(my_number) = maybe_number {
  println!("{}", my_number * 2); // 现在正常工作了!
} // 我们还可以添加一个else代码块来处理None情况

Result 类型

与 Option 类型相似,还有 Result 类型。Result 就像 Option 一样,但不仅仅是 Some 和 None,它可以是包含函数返回结果的 Ok,或者如果出现错误,它会有包含一个错误的 Err。这种错误也作为值返回的错误处理方式最好与 Go语言的方式进行比较。和 Rust 不一样,关键的区别在于 Go 语言中结果和 null-able 错误都会返回。这意味着忘记检查是否已经返回错误并使用结果,将导致运行时错误。

Rust 没有这个陷阱,因为像 Option 一样,必须先检查 Result 枚举的内容。因此,在发生错误时,不会误用结果。

强制初始化

大多数其他语言允许程序员将变量的声明和初始化分开,这样的后果是,程序员有时往往会忘记初始化这样的变量,例如在分支中。虽然也有一些语言会在编译器中会终止编译(Java)或发出警告(C, C++),但这些并不会阻止程序员通过将变量初始化为 null 或零值而使得编译器不报错、在运行时引起崩溃或更糟糕的结果以及让程序做错误的处理。

对于未初始化的变量绑定,Rust 将拒绝编译,从而防止运行时错误:

let a: &str;
println!("{}", a.len()); // Compilation error!
a = "Hello";

这将报错:error[E0381]: use of possibly uninitialized variable: *a

当然,null 初始化技巧仍然是可用的,现在需要使用 Option 类型,如前所述,需要对 None 类型进行显式处理。

如果可以,一旦声明变量就初始化你的绑定:

let a = "hello";
println!("{}", a.len());

Traits

Traits(类似于其他语言中的接口)可以描述为可执行某些操作的类型的抽象定义。例如,Rust 标准库定义了一个 fmt::Display trait 表示它们自己为字符串的类型。Traits 让 Rust 看起来像静态类型语言,可以用作通用函数和类型的约束。

思考下面的函数:使用字符串表示将一段整数写入文件:

fn write_list(out: &mut fs::File, numbers: &[i32]) -> io::Result<()> {
  for num in numbers {
    writeln!(out, "{}", num)?;
  }
  Ok(())
}

简单吧? 但是如果是无符号整数呢?字符串呢?浮点数? 自定义类型? 我们需要为所有类型的类型创建同样一个函数!

但是 Rust 可以使用一个类型参数为我们做到这一点:

fn write_list<W, T>(mut out: W, things: &[T]) -> io::Result<()>
  where W: io::Write,
        T: fmt::Display {
  for thing in things {
    writeln!(out, "{}", thing)?;
  }
  Ok(())
}

现在,此函数接受实现Display trait的任何类型。

我也可以使用W替换了一个类型参数&mut fs::File,并且必须实现 io::Write trait。 这使得更容易编写单元测试,因为不用使用fs api和临时文件,我们只是使用一个vector,因为它实现了io::Write。 请注意,W参数是所有而不是引用(&mut W),因为W的io::Write的实现是所有可变引用的类型的io::Write实现!

其它翻译版本 (1) 加载中

引用

如果你以前用过C/C++,那你或许理解指针。引用(References),是一种可以通过其读写一块内存而不用关心其如何分配的东西。然而Rust中的引用和C中的指针不太一样,因为引用不能为null。

在我们了解引用存在的必要性以及工作模式之前,我想先解释一下所属(ownership)的概念。

其它翻译版本 (1) 加载中

所属

Rust和C相同的是,其程序中的数据被存在heap或者stack中,而且没有垃圾回收机制。其不同点是,Rust规定了特定的内存管理方式:其子过程(subroutine)的所属者(owner)负责分配和释放子过程的内存。

这种内存管理模式防止了忘记释放内存、释放两次以及释放后再次使用内存的情况,进而消除了烦人的安全bug。这是Rust语言内置的机制,并且用这个替换了垃圾回收器,这是一种在编译期间安全管理内存的方式。

其它翻译版本 (1) 加载中 本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务

  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【计算机/互联网|】Nginx出现502错误(2020-01-20 21:02)
【计算机/互联网|】网站运营全智能软手V0.1版发布(2020-01-20 12:16)
【计算机/互联网|】淘宝这是怎么了?(2020-01-19 19:15)
【行业动态|】谷歌关闭小米智能摄像头,因为窃听器显示了陌生人家中的照片(2020-01-15 09:42)
【行业动态|】据报道谷歌新闻终止了数字杂志,退还主动订阅(2020-01-15 09:39)
【行业动态|】康佳将OLED电视带到美国与LG和索尼竞争(2020-01-15 09:38)
【行业动态|】2020年最佳AV接收机(2020-01-15 09:35)
【行业动态|】2020年最佳流媒体设备:Roku,Apple TV,Firebar,Chromecast等(2020-01-15 09:31)
【行业动态|】CES 2020预览:更多的流媒体服务和订阅即将到来(2020-01-08 21:41)
【行业动态|】从埃隆·马斯克到杰夫·贝佐斯,这30位人物定义了2010年代(2020-01-01 15:14)
联系我们

Q Q: 7090832

电话:400-0011-990

邮箱:7090832@qq.com

时间:9:00-23:00

联系客服
商家入住 服务咨询 投拆建议 联系客服
0577-67068160
手机版

扫一扫进手机版
返回顶部