一个小众现象是如何连续五年成为StackOverflow最受欢迎的语言的
有时候旧东西比你想象的更有价值。
来自过去的技术来拯救未来。这就是《Rust》的创造者格雷顿·霍尔(Graydon Hoare)所说的他想要实现的目标。
这是Rust的关键特征之一:使用学术界众所周知但很少在当代编程语言中实现的技术。老旧、可靠、有时被遗忘的技术。但最重要的是,它运行得非常好。
这些技术主要用于一件事:安全。
听起来无聊吗?如果你问社区里的人,答案是否定的。根据今年的StackOverflow开发人员调查,高达86.1%的Rust开发人员最喜欢这门语言,使它成为自2016年以来最受欢迎的语言。
你可能会认为软件开发人员是这个星球上最具创新精神的人。然而,Rust与“快速行动,打破常规”的咒语正好相反。尽管如此,Rust开发人员几乎可以保证学习他们以前从未听说过的概念。
从一些开发人员使用代数数据类型进行系统编程的新奇性,到Rust自己的内存安全方法:每个开发人员都可以找到一些新的、非常有用的东西来学习。还有更多的理由爱上Rust。
无需垃圾收集,更安全的内存
每一种编程语言都面临着一个挑战,即以一种安全有效的方式管理计算机的内存。例如,Python有一个垃圾收集器,它会在程序运行时不断查找不再使用的内存并清理它。
在其他语言中,如C和c++,程序员必须显式地分配和释放内存。由于所有与内存相关的问题都在程序运行之前被清除,因此这种方法对于优化性能更好。
另一方面,内存是开发人员需要一直考虑的另一件事。这就是为什么用C编写程序比用Python要花更长的时间的原因之一,即使它在一天结束时做的事情是一样的。
Rust采用另一种方式:在编译时通过所有权系统分配内存。这是一种巧妙的技巧,可以确保清理未使用的数据,而不必强迫程序员一直考虑分配和释放内存。
Rust使用旧的技术进行有效的内存管理
基本上,所有权是三个规则的集合:
Rust中的每个值都有一个名为owner的变量。
一次只能有一个所有者。
当所有者超出作用域时,值将被删除,从而释放内存。
一个简单的例子是在Rust中赋值一个vector:
fn main() {
let a = vec![1, 2, 3];
let b = a;
println!("a: {:?}", b);
}
在第二行中,创建所有者为a的向量[1,2,3]。之后,b成为向量的所有者。因为在print语句中调用了正确的所有者,这个程序在执行时编译并返回预期的结果:
a: [1, 2, 3]
另一方面,你可以尝试调用vector和它之前的所有者a,就像这样:
fn main() {
let a = vec![1, 2, 3];
let b = a;
println!("a: {:?}", b, a);
}
在这种情况下,编译器抛出一个错误,因为在第三行中已经删除了a。这个主题有更多的深度,但这是基本的思想。
相比之下,Python会在第二种情况下运行。它的垃圾收集器只会在最后一次调用它之后才丢弃,这对开发人员来说很好,但在内存空间方面就不太好了。
在C中,事情会稍微复杂一些:您必须为a分配内存空间,然后将其指向vector,然后为b分配更多的内存空间,将b指向a,最后在您完成时释放a和b占用的空间。
从这个意义上说,Rust到内存的方法是开发速度和性能之间的妥协。虽然它不像Python那么容易编写,但是一旦您理解了所有权的概念,它就不会像C那样笨拙。
另一方面,效率是相当惊人的:例如,开发团队Tilde在Rust中重写了一些JavaHTTP片段后,设法减少了90%的内存使用。
谁说Rust不能吸引人?
静态类型而不太难看
这几乎是动态类型和静态类型爱好者之间的一场宗教战争。虽然用具有动态类型的语言编写软件要容易得多,但代码可能很快变得难以维护。这就是为什么Python代码比C代码更难维护的原因之一。
另一方面,必须声明每个变量的类型C-style会非常烦人。如果你曾经尝试在返回C浮点类型的函数中使用double,你就会明白我的意思。
Rust走了一条中间的路:它是一个静态类型系统,但它只需要程序员指定顶级类型,如函数参数和常量。在函数体内部,允许使用python风格的类型推断。
Rust的一个特别有用的特性是,它也没有任何类型。这允许您在编译时处理异常,从而保证程序在最终用户中平稳运行。考虑这个例子,我们可以得到一个人的全名,不管他是否有中间名:
fn get_full_name(fname: &str, mname: Option, lname: &str) -> String {
match mname {
Some(n) => format!("{} {} {}", fname, n, lname),
None => format!("{} {}", fname, lname),
}
}
fn main() {
println!("{}", get_full_name("Ronald", None, "McDonald"));
println!("{}", get_full_name("Dwight", Some("P."), "Eisenhower"));
}
虽然在其他语言中也有None的版本,但它以一种简洁的方式展示了Rust的雄心:在保持代码尽可能持久和可维护性的同时,不让编写变得过于困难。
一种极好的系统编程方法
虽然Python是一种通用编程语言,但Rust像C一样,是用于系统编程的。虽然Rust不是为最终用户制作应用程序的理想语言,但它非常适合构建为其他软件提供服务的软件。
因此,效率是Rust的核心。最好的例子是零成本抽象,它解释代码的同时将内存使用保持在最低限度。正如c++的发明者Bjarne Stroustrup所说:“不用的东西,不用付钱。”而且:你所使用的,你不能再更好的手动代码。”
例如,考虑在Python中把不超过1000的所有整数相加:
sum(range(1000))
这在每次代码运行时都要进行1000次迭代和添加—您可以想象这会使代码变慢多少。相比之下,在Rust方面考虑同样的事情:
(0..1000).sum()
这个编译成常数499500。实际上,内存使用量已经减少了1 / 1000。
虽然这些抽象在C语言中也存在,但是Rust大量地使用了它们——事实上,一个目标就是在语言中添加尽可能多的零成本抽象。在这个意义上,Rust有点像下一个级别的C。
C已经存在了40多年,Rust的目标也是如此。Rust非常强调向后兼容,所以今天您仍然可以在Rust 1.0中运行代码。同样地,如果您今天编写Rust代码,您应该仍然能够在二十年后运行它。Rust不会生锈!
一个小而不可思议的社区
它强调安全性和可持续性,所有漂亮的细节都说明了这一点,也难怪Dropbox在《Rust》中重写了许多核心结构。Rust的第一个大赞助商Mozilla在其中编写了Firefox的重要部分。微软认为C和c++对于关键任务软件不再安全,并在Rust问题上投入了越来越多的资金。
不仅是大公司,对Rust的热爱也影响到个人程序员。尽管到目前为止StackOverflow的调查对象中只有5%的人使用Rust,但这些开发人员对该语言非常有热情。
这是有原因的。不仅语言规范和编译器是经过深思熟虑的。有rustup安装和管理工具链。还有Cargo,这是一个命令行工具,它随Rust安装而来,帮助管理依赖关系、运行测试和生成文档。
板条箱。用户可以共享和发现库和文档。在rs中记录它们。有来自Clippy的编译器lints和来自rustfmt的自动格式化。
除此之外,还有官方和非官方的聊天、看板、用户论坛、StackOverflow问题和世界各地的会议。在一个把友善看得高于一切的社区里,还有什么更好的要求吗?
缺点:在你会走路之前,你需要先跑
关于Rust的一个令人沮丧的事情是高昂的启动成本。虽然在大多数语言中,你需要一到两天的时间来学习,但这更像是一到两周的“Rust”。
这是因为有许多其他语言没有使用的新概念,而且在编译时通常会有很多错误。您需要在第一天就处理所有异常,不能像在Python中那样编写一个临时代码来运行并在以后添加异常。
此外,由于Rust仍然是相当新的,并不是所有您可能需要的库都在那里。除了官方文档和StackOverflow上的各种问题,也没有那么多的教程。
好消息是,一旦你掌握了这些概念并编译了你的程序,它就会像魔法一样运行。另外,考虑到向后兼容性,它应该在20年内仍然可以工作。
考虑到您的代码的可持续性,以及Rust是由许多大公司支持的事实,一到两周的预先学习可能是值得的,尽管有缺点。
This type of Rust won’t make your ship sink.
底线是:无所畏惧地进行攻击
Rust不仅仅是安全。但难以否认的是,它的许多核心概念旨在消除内存泄漏和其他安全问题。在一个软件就是一切的时代,安全是必须的。
可能每一种即将到来的语言都有其发展空间:Go越来越多地填充Python和Java的空间,Julia在数据科学领域追逐Python,而Rust则在Python和c++的领域中成长。Rust的特别之处在于它令人难以置信的社区,它的创新特性,以及它被设计用于未来几十年的事实。
还有很多工作要做,其中只有一小部分可以而且将会生锈。今天的新语言有很大的机会坚持一段时间,即使其他语言也会在未来几年出现。但如果我必须把名片放在一种语言上,Rust将是一个安全的赌注。
领取专属 10元无门槛券
私享最新 技术干货