什么是Rust,为什么它如此受欢迎?

发布于:2021-01-07 10:25:30

0

730

0

Rust 编程 后端

Rust已连续四年成为Stack Overflow最受欢迎的语言,这表明许多有机会使用Rust的人都爱上了它。但是,大约97%的未使用Rust的调查对象可能会想,“与Rust有何关系?”

简短的答案是,Rust解决了许多其他语言中存在的痛点,这为有限的缺点方面迈出了坚实的一步。

我将展示一个示例,介绍Rust为其他编程语言的用户提供的功能以及当前的生态系统。在Rust-land上,玫瑰花还不是全部,所以我也谈到了缺点。

来自动态类型的语言

喜欢动态类型系统还是静态类型系统的程序员之间的争论可能还会持续数十年,但是很难争论静态类型的好处。由于人们对当今更大的代码库中的动态键入的当前状态感到沮丧,因此您只需要查看诸如TypeScript之类的语言或诸如Python的类型提示之类的功能的兴起。静态类型的语言允许对数据及其行为进行编译器检查的约束,从而减轻认知开销和误解。

这并不是说所有静态类型系统都是等效的。许多静态类型的语言旁边都有一个大星号:它们允许使用NULL概念。这意味着任何值都可能是它所说的或什么都没有,有效地为每种类型创建了第二种可能的类型。与Haskell和其他一些现代编程语言一样,Rust使用可选类型对这种可能性进行编码,并且编译器要求您处理None情况。这可以防止发生可怕的TypeError:无法读取null运行时错误(或等效语言)的属性'foo',而是将其提升为可以在用户看到它之前解决的编译时错误。这是一个向某人打招呼的函数示例,无论我们是否知道他的名字;如果我们忘记了匹配中的None情况,或者试图像使用始终存在的String值一样使用name,则编译器会抱怨。

fn greet_user(name: Option<String>) {    
    match name {        
        Some(name) => println!("Hello there, {}!", name),   
        None => println!("Well howdy, stranger!"),
    }
}

Rust的静态类型尽最大努力摆脱程序员的困扰,同时鼓励长期的可维护性。 一些静态类型的语言给程序员带来了沉重的负担,要求他们多次重复变量的类型,这阻碍了可读性和重构。 其他静态类型语言允许整个程序类型推断。 虽然在初始开发过程中很方便,但是这会降低编译器在类型不再匹配时提供有用的错误信息的能力。 Rust可以从这两种样式中学习,并要求顶层项(如函数参数和常量)具有显式类型,同时允许在函数体内部进行类型推断。 在此示例中,Rust编译器可以推断出double,2和1的类型,因为val参数和返回类型被声明为32位带符号整数。

fn simple_math(val: i32) -> i32 { 
    let twice = val * 2;
    twice - 1
}

来自垃圾收集语言

使用系统编程语言的最大好处之一就是可以控制低级的细节。

Rust使您可以选择将数据存储在堆栈或堆上,并在编译时确定何时不再需要内存并可以对其进行清理。这样可以有效利用内存,并实现更高性能的内存访问。 Tilde是Skylight产品中Rust的早期生产用户,他发现通过在惯用的Rust中重写某些Java HTTP端点,他们能够将内存使用量从5GiB减少到50MiB。当云提供商对增加的内存或额外的节点收取高昂的价格时,这样的节省很快就会加起来。

无需连续运行垃圾收集器,Rust项目非常适合被其他编程语言通过外部功能接口用作库。这使现有项目可以用快速的Rust代码替换对性能至关重要的代码,而不会产生其他系统编程语言固有的内存安全风险。某些项目甚至已使用这些技术在Rust中进行了增量重写。

通过直接访问硬件和内存,Rust是嵌入式和裸机开发的理想语言。您可以编写底层代码,例如操作系统内核或微控制器应用程序。在这些特别具有挑战性的环境中,Rust的核心类型和功能以及可重用的库代码非常出色。

来自其他系统编程语言

对于许多人来说,Rust在很大程度上被视为其他系统编程语言(例如C或C ++)的替代。与这些语言相比,Rust可以提供的最大好处是借阅检查器。这是编译器的一部分,负责确保引用不会超出引用的数据寿命,并有助于消除由于内存不安全而导致的所有类型的错误。

与许多现有的系统编程语言不同,Rust不需要您将所有时间都花在细节上。 Rust力求拥有尽可能多的零成本抽象,这种抽象与等效的手写代码具有同等的性能。在此示例中,我们展示了如何使用迭代器(一种主要的Rust抽象)来简洁地创建一个包含前十个平方数的向量。

let squares: Vec<_> = (0..10).map(|i| i * i).collect();

当安全的Rust无法表达某些概念时,您可以使用不安全的Rust。这样可以释放一些额外的功能,但作为交换,程序员现在有责任确保代码真正安全。然后,可以将这种不安全的代码包装在更高级别的抽象中,以确保对抽象的所有使用都是安全的。

使用不安全的代码应该是一个经过深思熟虑的决定,因为正确使用它需要与负责避免未定义行为的任何其他语言一样多的思考和关心。最小化不安全代码是最小化由于内存不安全而导致段错误和漏洞可能性的最佳方法。

系统编程语言有一个隐含的期望,那就是它们将永远有效。尽管某些现代开发并不需要那么长的寿命,但许多企业希望知道其基本代码库可在可预见的将来使用。 Rust意识到了这一点,并围绕向后兼容性和稳定性做出了有意识的设计决策。这是为未来40年设计的语言。

Rust生态系统

Rust的经验比语言规范和编译器还重要。创建和维护生产质量软件的许多方面都被视为一流公民。可以通过rustup安装和管理多个并发的Rust工具链。 Rust安装随附Cargo,这是一个命令行工具,用于管理依赖项,运行测试,生成文档等。由于默认情况下依赖项,测试和文档可用,因此它们的用法很普遍。 crates.io是用于共享和发现Rust库的社区站点。发布到crates.io的任何库都将建立其文档并在docs.rs上发布。

除了内置工具外,Rust社区还创建了许多开发工具。基准测试,模糊测试和基于属性的测试都可以在项目中轻松访问和很好地使用。 Clippy提供了额外的编译器棉绒,而rustfmt提供了自动惯用格式。 IDE支持是健康的,并且每天都在变得越来越强大。

超越技术要点,Rust拥有一个充满活力的热情社区。人们可以通过几种官方和非官方途径获得帮助,例如聊天,用户论坛,Rust subreddit,当然还有Stack Overflow问题和解答以及聊天室。 Rust拥有一个由出色的审核小组执行的行为准则,以确保正式场所受到欢迎,而且大多数非官方场所也观察到类似情况。

在离线状态下,Rust在全球举行了多个会议,例如RustConf,Rust Belt Rust,RustFest,Rust Latam,RustCon Asia等。

这并不全是玫瑰

Rust强大的类型系统和对内存安全的重视(所有这些工作都是在编译时强制执行的),这意味着在编译代码时出现错误非常普遍。对于不习惯这种自以为是的编程语言的程序员来说,这可能是一种令人沮丧的感觉。但是,Rust开发人员花费了大量时间来改进错误消息,以确保它们清晰且可操作。阅读Rust错误时,不要让您的眼睛蒙上眼睛!

听到某人抱怨自己一直在“与借阅检查员打架”是很常见的。尽管这些错误可能令人沮丧,但重要的是要认识到,所确定的每个位置都有可能以不执行相同检查的语言来引入错误和潜在漏洞。

在此示例中,我们创建了一个包含名称的可变字符串,然后引用该名称的前三个字节。尽管该引用非常出色,但我们尝试通过清除字符串来对其进行突变。现在无法保证引用指向有效数据并对其取消引用可能导致未定义的行为,因此编译器会阻止我们:

fn no_mutable_aliasing() { 
    let mut name = String::from("Vivian");    
    let nickname = &name[..3];
    name.clear();   
    println!("Hello there, {}!", nickname);
}


error[E0502]: cannot borrow `name` as mutable because it is also borrowed as immutable
 --> a.rs:4:5
  |
3 |     let nickname = &name[..3];
  |                     ---- immutable borrow occurs here
4 |     name.clear();
  |     ^^^^^^^^^^^^ mutable borrow occurs here
5 |     println!("Hello there, {}!", nickname);
  |                                  -------- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.

有用的是,错误消息包含了我们的代码,并尽最大努力解释问题,指出确切的位置。

Rust的原型解决方案可能具有挑战性,因为它具有静态类型的性质,并且因为Rust需要覆盖100%的条件,而不仅仅是99%。边缘案例必须具有适用的代码,即使程序员尚不知道幸福的道路应该做什么。在早期开发中,这些极端情况通常可以通过使程序崩溃来解决,然后可以在以后添加严格的错误处理。这与Ruby等语言不同,工作流中的开发人员经常在REPL中试用代码,然后将其移至原型,而完全不考虑错误情况。

Rust仍然是相对较新的,这意味着某些所需的库可能尚不可用。好处是,有足够的沃土来开发这些所需的库,甚至可能利用相关计算机科学领域的最新发展。由于具有此功能和Rust的功能,Rust的某些库(例如正则表达式板条箱)是所有语言中同类产品中最好的。

尽管Rust对稳定性和向后兼容性具有坚定的承诺,但这并不意味着该语言已定稿。一个特定的问题可能无法使用语言功能,这将使其表达起来更加简单,甚至可能表达出来。例如,Rust具有异步期货已超过三年,但是对语言本身的稳定异步/等待支持仅几个月之久。

Rust编译器基于LLVM构建,这意味着目标平台的数量将小于C或C ++。

来加入我们吧!

无论您现在喜欢哪种编程语言,都一定会对Rust产生兴趣或引起您的兴趣。这就是为什么我和其他人非常喜欢Rust的原因,还有很多。如果您正在寻找项目中的额外结构,更快或更高效的代码,或者能够更快,更安全地编写高性能代码的能力,那么现在该看看Rust是否将成为您的下一个最受欢迎的语言!