我为什么要选择Rust

我为什么要选择Rust,第1张

你好,很高兴为你解答。

专访资深程序员庄晓立:我为什么要选择Rust?

Rust是由Mozilla开发的注重安全、性能和并发性的编程语言。这门语言自推出以来就得到了国内外程序员的大力推崇。Rust声称解决了传统C语言和C++语言几十年来饱受责难的内存安全问题,同时还保持了极高的运行效率、极深的底层控制、极广的应用范围。但在国内有关Rust的学习文档并不多见,不久前,笔者联系上了Rust10版本代码贡献者庄晓立(精彩博文:为什么我说Rust是靠谱的编程语言),请他分享Rust语言特性以及学习经验。

CSDN:你是从什么时候开始接触Rust语言的?是什么地方吸引了你?

庄晓立:我大概从2013年后半年开始深入接触Rust语言。它居然声称解决了传统C语言和C++语言几十年来饱受责难的内存安全问题,同时还保持了极高的运行效率、极深的底层控制、极广的应用范围。

其ownership机制令人眼前一亮,无虚拟机(VM)、无垃圾收集器(GC)、无运行时(Runtime)、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争(Data Race)……所有这些,都深深地吸引了我——这个十多年以来深受C语言折磨的痛并快乐着的程序员。

CSDN:在你看来,Rust是怎样的一门语言?它适合开发什么类型的项目?为何你会说Rust不惧怕任何竞争对手,它既能取代C语言地位;又可挑战C++市场,还可向Java、Python分一杯羹?与这些语言相比,Rust有哪些优越的特性?

庄晓立:Rust是一门系统编程语言,特别适合开发对CPU和内存占用十分敏感的系统软件,例如虚拟机(VM)、容器(Container)、数据库/游戏/网络服务器、浏览器引擎、模拟器等,而这些向来主要都是C/C++的传统领地。

此外,Rust在系统底层开发领域,如裸金属(bare metal)、 *** 作系统(OS)、内核(kernel)、内核模块(mod)等,也有强劲的实力,足以挑战此领域的传统老大C语言。Rust丰富的语言特性、先进的设计理念、便捷的项目管理,令它在上层应用开发中也能大展拳脚,至少在运行性能上比带VM和GC的语言要更胜一筹。无GC实现内存安全机制、无数据竞争的并发机制、无运行时开销的抽象机制,是Rust独特的优越特性。

其他语言很难同时实现这些目标,例如传统C/C++无法保证内存安全,Java/Python等无法消除运行时开销。但Rust毕竟还是很年轻的项目,它释放影响力需要时间,被世人广泛接受需要时间;它的潜力能否爆发出来,需要时间去检验。我们只需耐心等待。

CSDN:Rust在国内有没有具体的实际使用案例?

庄晓立:因为Rust10正式版刚刚发布不足一月,在国内影响力还不大,我们不能苛求它在国内有实际应用案例。但是在国外,一两年前就已经有OpenDNS和Skylight把Rust应用在生产环境。还有浏览器引擎Servo、Rust编译器和标准库、项目管理器Cargo等“两个半大型应用案例”。这些足够说明Rust语言的成熟和实用。

CSDN:你参与了Rust10版本代码贡献,目前该版本正式版已经发布,对此你感觉如何?这门语言是否已经达到比较成熟的阶段?

庄晓立:我积极参与了Rust语言开源项目,多次贡献源代码,曾连续三次出现在Rust官方博客公布的Rust 10 alpha、Rust 10 beta和Rust 10正式版的贡献者名单中。在Rust 10正式版出台的过程中及此前的很长一段时间,开发者付出了极大的努力,确保Rust 10正式版在Semver 20规范下,务必保持向后兼容性,除非遇到重大Bug不得不修复。

我认为,在10正式发布之后,Rust就已经进入了比较成熟的阶段。而且,Rust还在快速迭代发展过程中,10发布6周后将发布11,再6周后将发布12,必然会一步一个台阶,越来越成熟稳定。

CSDN:除了功能优先级以外,在你看来,Rust正在朝什么方向发展?未来的Rust可以期待什么样的特性?

庄晓立:Rust一定会沿着“确保内存安全、无运行开销、高效实用”的既定方向持续发展。在短期内值得期待的语言特性有:动态Drop、偏特化、继承、改进borrow checker、改进宏和语法扩展。短期内值得期待的其他特性有:增强文件系统API、提供内存申请释放API、更好地支持Windows和ARM、更快的编译速度、更方便的二进制分发机制(MUSL)、更实用的工具等等。

CSDN:据我了解,你之前也比较推崇Go语言,为何想到放弃Go转向Rust?

庄晓立:推崇Go语言还谈不上,不过我曾经尝试努力接受Go语言,2011底年开始我曾经花费将近半年时间深度关注Go开发进程,提了很多具体的改进意见和建议,也曾经多次尝试贡献源代码。后来考虑到Go语言的设计理念跟我偏差太大,其社区也不太友好,慢慢地疏远了它。我曾经写过一篇博客《我为什么放弃Go语言》,谈到了很多具体的原因。

CSDN:国内,参与Rust代码贡献的开发者多吗?有核心的人员吗?有哪些社区在维护Rust?

庄晓立:国内参与Rust代码贡献的开发者并不多,但也不少,官方的贡献者名单中也偶见几个貌似国人的名字。Rust的核心开发人员基本上都是Mozilla公司的员工,他们专职负责开发维护Rust语言和相关的项目,Rust社区也主要是他们参与组织和管理的。社区人员讨论主要集中在GitHub项目主页RFC/PR/Issue官方、Discuss论坛/IRC、Reddit、HN、StackOverflow等。

ps5可以玩rust,因为rust这款游戏支持PS4,而PS5是兼容PS4游戏的,所以玩家可以在PS5上玩rust。《Rust》是由Facepunch Studios公司采用Unity 3D制作的一款第一人称生存网络游戏,可以建设个人服务器。

本作的游戏体验非常黑暗。游戏中玩家之间的利用、背叛、抢夺、杀戮很常见,可以说如果你不是和一个好基友一起进行游戏,你的整个游戏过程都将会非常艰辛,必须时刻保持着高度的戒心。

RUST玩家的注意事项。

玩家在玩rust时要注意,该游戏是采取PVP模式玩法的,玩家看见其他玩家可以选择结伴、无视、或是直接杀了对方,抢夺其身上的任何资源。游戏除了注重战斗部分外,还拥有非常丰富的生存要素。玩家在游戏中除了要防范动物,科学家、玩家的袭击,并依靠各类物品进行生存。

原文链接:The Rust Programming Language

作者:rust 团队

译文首发链接:zhuanlanzhihucom/p/516660154

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

中间加了一些对于 JavaScript 开发者有帮助的注解。在学习 Rust 的代码时,尤其是有一些经验的开发者,一般都会去看一些相对简单的库,或者项目去学习。Rust 的原生语法本身并不复杂,有一定的 TypeScript 经验的开发者,应该通过看一些教程,都能开始熟悉基本的语法。反而是宏相关内容,虽然就像本文写的,大部分开发者不需要自己去开发宏,但是大家使用宏,和看懂别人代码的主体逻辑,几乎是绕不开宏的。虽然宏在 rust 里属于“高级”内容,但是因为其和 rust 本身语法的正交性,Hugo 认为,反而应该早一些学习。并且,如果一个 JavaScript 开发者之前接触过代码生成器、babel,对这一章的内容反而会比较亲切。

Derive 宏、attribute 宏特别像 rust 里的装饰器。从作用上,和一般库提供的接口来看,也特别像。所以如果之前有装饰器的经验的开发者,对这一章节应该也会比较亲切。

我们一个个来讨论这些内容,但是首先,我们看既然我们已经有了函数,我们为什么需要这些特性。

基本上,宏是指一些代码可以生成另一些代码,这一块的技术一般称为元编程(Hugo 注:代码生成器也属于这一类技术)。在附录 C,我们讨论了 derive 属性,可以帮助你生成一系列的 trait。整本书我们也在用 println! 和 vec! 宏。这些宏在编译时,都会展开成为代码,这样你就不需要手写这些代码。

元编程可以帮助你减少手写和维护的代码量,当然,函数也能帮助你实现类似的功能。但是,宏有函数没有的威力。

宏不好的地方在于,宏很复杂,因为你要用 rust 代码写 rust 代码(Hugo 注:任何元编程都不是简单的事儿,包括 JS 里的。)。因为这种间接性,宏的代码要更难读、难理解、难维护。(Hugo 注:个人学 rust,感觉最难不是生命周期,因为生命周期的问题,可以通过用一些库绕过去,或者无脑 clone,如果是应用程序,则可以通过使用 orm 和数据库来绕过很多生命周期的问题。反而是宏,因为稍微有点规模的代码的,都有一大堆宏。宏最难的不是语法,而是作者的意图,因为本质是他造了一套 DSL)

另一个和函数不一样的地方是,宏需要先定义或者引入作用域,而函数可以在任何地方定义和使用。

我们可以通过 vec! 宏来创建任意类型的 vector,例如 2 个 integer,或者五个 string slice

一个简化的 vec! 宏:

#[macro_export] 标注指明了这个宏在 crate 的作用域里可用。没有这个标注,宏不会被带入到作用域里。

macro_rules! 后面就是宏的名字。这里只有一种模式匹配的边(arm):( (( (x:expr ), ) ,=> 后面是这个模式对应要生成的代码。如果这个模式匹配成功,对应的代码和输入的参数组成的代码就会生成在最终的代码中。因为这里只有一种边,所以只有这一种可以匹配的条件。不符合这个条件的输入,都会报错。一般复杂的宏,都会有多个边。

这里匹配的规则和 match 是不一样的,因为这里的语法匹配的是 rust 的语法,而不是 rust 的类型,或者值。更全的宏匹配语法,见文档。

对于 宏的输入条件 ( (( (x:expr ), ),()内部是匹配的语法,expr表示所有Rust的表达式。() 内部是匹配的语法,expr 表示所有 Rust 的表达式。()内部是匹配的语法,expr表示所有Rust的表达式。() 后面的都喊表示这个变量后面有可能有逗号, 表示前面的模式会出现一次或者多次。(Hugo 注:像不像正则?宏语法其实挺简单的,不要被高级唬住了。当然,宏还是难的,宏要考虑的问题本身是一个复杂的问题。)

当我们调用:vec![1, 2, 3]; 时,$x 模式会匹配 3 个表达式 1 , 2 和 3。

现在我们看一下和这个边匹配的生成代码的部分:

在 ()里的tempvecpush(() 里的 temp_vecpush(()里的tempvecpush(x); 就是生成的代码的部分。 号仍然表示生成零个和多个,这个匹配的具体个数,要看匹配条件命中的个数。

你传任意参数,最后就生成符合上面条件的代码。

虽然过程宏有三种:custom derive、attribute-like 和 function-like,但是原理都是一样的。

如果要创建过程宏,定义的部分需要在自己的 crate 里,并且要定义特殊的 crate 类型。(Hugo 注:相当于定义了一个 babel 插件,只不过有一套 rust 自己的体系。这些宏会在编译的时候,按照书写的规则,转成对应的代码。所有的宏,都是代码生成的手段,输入是代码,输入是代码。)这种设计,我们有可能会在未来消除。

下面是一个过程宏的例子:

过程宏接收一个 TokenStream,输出一个 TokenStream。TokenStream 类型定义在 proc_macro 里,表示一系列的 tokens。这个就是这种宏的核心机制,输入的代码(会被 rust) 转成 TokenStream,然后做一些按照业务逻辑的 *** 作,最后生成 TokenStream。这个函数也可以叠加其他的属性宏(#[some_attribute], 看起来像装饰器的逻辑,也可以理解为一种链式调用),可以在一个 crate 里定义多个过程。(Hugo 注:搞过 babel 的同学肯定很熟悉,一样的味道。没搞过的同学,强烈建议先学学 babel。)

下面我们来看看不同类型的过程宏。首先从自定义 derive 宏开始,然后我们介绍这种宏和其他几种的区别。

我们创建一个 crate 名字叫 hello_macro,定义一个 HelloMacro 的 trait,关联的函数名字叫 hello_macro。通过使用这个宏,用户的结构可以直接获得默认定义的 hello_macro 函数,而不需要实现这个 trait。默认的 hello_macro 可以打印 Hello, Macro! My name is TypeName!,其中 TypeName 是实现这个 derive 宏的结构的类型名称。

创建这个宏的过程如下,首先

然后定义 HelloMacro trait

这样我们就有了一个 trait,和这个triat 的函数。用户可以通过这个 trait 直接实现对应的函数。

但是,用户需要每次都实现一遍 hello_macro。如果 hello_macro 的实现都差不多,就可以通过 derive 宏来是实现。

因为 Rust 没有反射机制,我们不可以在执行时知道对应类型的名字。我们需要在编译时生成对应的代码。

下一步,定义过程宏。在这个文章编写时,过程宏需要在自己的 crates 里。最终,这个设计可能改变。关于 宏 crate 的约定是:对于一个名为 foo 的 crate,自定义 drive 宏的crate 名字为 foo_derive。我们在 hello_macro 项目中创建 hello_macro_derive crate。

我们的两个的 crate 关联紧密,所以我们在 hello_macro crate 里创建这个 crate。如果我们要改变 hello_macro 的定义,我们同样也要更改 hello_macro_derive 的定义。这两个 crates 要隔离发布。当用户使用时,要同时添加这两个依赖。为了简化依赖,我们可以让 hello_macro 使用 hello_macro_derive 作为依赖,然后导出这个依赖。但是,这样,如果用户不想使用 hello_macro_derive,也会自动添加上这个依赖。

下面开始创建 hello_macro_derive,作为一个过程宏 crate。需要添加依赖 syn 和 quote。下面是这个 crate 的 Cargotoml。

在 librs 里添加下述代码。注意,这个代码如果不增加 impl_hello_macro 的实现是通不过编译的。

注意,这里把代码分散成两部分,一部分在 hello_macro_derive 函数里,这个函数主要负责处理 TokenStream,另一部分在 impl_hello_macro,这里负责转换语法树:这样编写过程宏可以简单一些。在绝大部分过程宏立,对于前者的过程一般都是一样的。一般来说,真正的区别在 impl_hello_macro,这里的逻辑一般是一个过程宏的业务决定的。

我们引入了三个 crates: proc_macro, syn 和 quote。proc_macro 内置在 rust 立,不需要在 Cargotoml 中引入。proc_macro 实际是 rust 编译器的一个接口,用来读取和 *** 作 Rust 代码。

syn crate 把 Rust 代码从字符串转换为可以 *** 作的结构体。quote crate 把 syn 数据在转回 Rust 代码。这些 Crate 可以极大简化过程宏的编写:写一个 Rust 代码的 full parser 可不是容易的事儿!

当在一个类型上标注 [derive(HelloMacro)] 时,会调用 hello_macro_derive 函数。之所以会有这样的行为,是因为在定义 hello_macro_derive 时,标注了 #[proc_macro_derive(HelloMacro)] 在函数前面。

hello_macro_derive 会把输入从 TokenStream 转换为一个我们可以 *** 作的数据结构。这就是为什么需要引入 syn 。sync 的 parse 函数会把 TokenStream 转换为 DeriveInput。

上述这个结构的意思是:正在处理的是 ident(identifier, 意味着名字)为 Pancakes 的 unit struct。其他的字段表示其余的 Rust 代码。如果想了解更详细的内容,请参考。

接下来,我们就要开始定义 impl_hello_macro。这个函数实现了添加到 Rust 代码上的函数。在我们做之前,注意 derive macro 的输出也是 TokenStream。返回的 TokenStream 就是添加完代码以后的代码。当编译 crate 时,最终的代码,就是处理完成的代码了。

你也许也会发现,这里调用 syn::parse 时使用了 unwrap,如果报错就中断。这里必须这么做,因为最终返回的是 TokenStream,而不是 Result。这里是为了简化代码说明这个问题。在生产代码,你应该处理好报错,提供更详细的报错信息,例如使用 panic! 或者 expect。

下面是代码:

通过上面的代码,cargo build 就可以正常工作了。如果要使用这个代码,需要把两个依赖都加上。

现在执行下面的代码,就可以看到 Hello, Macro! My name is Pancakes!

下一步,我们来 探索 其他类型的过程宏。

属性宏和 derive 宏类似,但是可以创造除了 derive 意外的属性。derive 只能作用于 structs 和 enums,属性宏可以作用于其他的东西,比如函数。下面是一个属性宏的例子:例如你制作了一个名为 route 的属性宏来在一个web 框架中标注函数。

#[route] 是框架定义的过程宏。定义这个宏的函数类似:

这里,有两个参数,类型都是 TokenStream。第一个是属性的内容,GET, "/" 部分,第二个是标注属性宏传入的语法部分,在这个例子里,就是剩下的 fn index() {}。

工作原理和 derive 宏是一样的。

函数宏的使用比较像调用一个 rust 函数。函数宏有点像 macro_rules! ,能提供比函数更高的灵活性。例如,可以接受未知个数的参数。但是,macro_rules! 只能使用在上述章节的匹配型的语法。而函数宏接受 TokenStream 参数作为入参,和其他过程宏一样,可以做任何变换,然后返回 TokenStream。下面是一个函数宏 sql!

这个宏接受 SQL 语句,可以检查这个 SQL 的语法是否正确,这种功能比 macro_rules! 提供的要复杂的多。这个 sql! 的宏可以定义为:

这个定义和自定义 derive 宏类似:接受括号内的 tokens,返回生成的代码。

好了,现在你有了一些可能不常用的 Rust 新工具,但是你要知道的是,在需要的场合,他们的运行原理是什么。我们介绍了一些复杂的话题,当你在错误处理或者别人的代码里看到这些宏时,可以认出这些概念和语法。可以使用这一章的内容作为解决这些问题的索引。

以太坊客户端Erigon宣布将结束对Erigon的Rust版本Akula的支持。Erigon团队近期发现,一个基于Rust语言的Ethereum实现将开放源代码,其范围几乎与Akula相同,并有一些相同/相似的构建模块。Erigon团队认为,该项目在开源后将更加受人支持与欢迎,其功能也将很快匹配和超越Akula。 与该项目背后拥有的资源和影响力相比,Erigon无法保证Akula能够吸引未来的资助,因此决定取消对Akula的技术、管理和资金支持。

时下如果语言界要评选一个网红的话,无疑会是Rust。Rust凭借着自己出色的安全性和高效性被各大平台所接纳,Linux内核,安卓底层开发,Windows底层开发相继都采纳并给出了对应的借口。微软的Windows也是,最近发布了Rust for Windows(windows-rs) v 09。更新中包括全面的调用支持,Rust可以直接原生调用任何Windows API可以极大的拓展Rust在Windows下的开发能力和范围。本文我们通过实例来学习Rust for Windows 。

概述

本次更新提供了很多新的特性和更新,根据官方的信息包括:

添加了对Win32和COM API的支持,统一了Windows板条箱。这些Windows API有新的项目win32metadata来添加。为了方便和统一,项目名称由“Rust/WinRT”更改为“Rust for Windows”。

添加了几个示例 ,演示了如何调用各种Windows API(包括Win32,COM和WinRT API)。

Windows 板条箱在cratesio发布,现在支持MIT或Apache双开源版权。

内置生成的binding,无需再手动编写。

Windows支持在Linux上构建。

Win32 API的许多改进和修复,例如对数组类型,各种字符串类型和更新的元数据的支持。

添加了对COM接口的更自然和惯用的支持,例如返回值,以及对涉及C样式联合和嵌套类型之类的其他API的支持。

缩短了构建时间并改善了错误处理。

保留原始的API大小写,这会影响使用Windows crate的现有代码。通过类似于QueryInterface的函数转换为通用函数,从而可以更安全,更方便地调用许多与COM相关的函数。

环境配置

Window板条箱使用需要首先要在Windows下配置Rust开发环境,还在Rust环境的安装也非常简单傻瓜化。

安装rustup

首先从Rust官方(rust-langorg)下载安装包rustup-initexe(记得下载当前Windows对应的32位或者64位版本)。

然后直接执行安装包,安装程序为自动配置好系统路径,以后就可以直接在命令行下使用了,比如cargo包管理器。

安装C++ build tools

Windows下的rust编译还依赖Microsoft C++ build tools工具,不安装,后面在编译时,会报错说“linkexe”无法找到。

需要从微软VS下载出下载vs_buildtools,选中C++工具和Windows SDK组件并安装。

安装VS Code及其Rust插件

另外,为了方便一般建议安装VS Code及其Rust插件:

crates-io国内源

配置Rust 板条箱的国内源,由于官方crates-io国内下载太慢,甚至容易失败,所以先配置国内源(比如ustc)

在用户目录C:\Users\CC\cargo创建一个config文件,内容配置为:

示例

首先,通过cargo创建一个新的Rust项目:

cargo new hello-chongchong

以上命令这将创建一个新目录并hello-chongchong创建基本项目框架目录和文件。

进入该目录,并使用--lib 命令嵌套创建依赖的库项目:

cargo new --lib bindings

然后通过

code

在VS Code打开该项目,截图如下:

修改项目Cargotoml文件中,添加以下依赖项,依赖项告诉Cargo现在它依赖于新创建的win库。

[dependencies]

bindings = {path = " bindings"}

现在,在win文件夹下的Cargotoml文件中,添加对Windows板条箱的依赖项,版本指定为最新的091。这样就可以通过允许Cargo打包下载,构建和缓存Windows支持。

[dependencies]

windows = "091"

[build-dependencies]

windows = "091"

然后在bindings目录下创建一个新的源文件buildrs,并输入一下源码:

// buildrs

fn main() {

windows::build!(

Windows::Win32::WindowsAndMessaging::MessageBoxA

);

}

在代码中,使用 windows::build 宏指定要使用的类型,可以再次列出需要使用的所API,Windows板条箱将直接元数据生成必要的绑定。

然后修改win/src目录中为以下代码:

windows::include_bindings!();

这样,就可以在主项目mainrs文件中,任意调用指定的Windows API。此处我们创建一个“Hello Chongchong!”消息对话框。

use bindings::Windows::Win32::WindowsAndMessaging::{MessageBoxA, MESSAGEBOX_STYLE};

fn main() {

unsafe {

MessageBoxA(None, "Hello Chongchong!", "Message", MESSAGEBOX_STYLE::MB_OK);

}

}

注意,任何Win32函数和COM接口方法,都需要用unsafe方式调用。

然后通过cargo build编译该项目,并通过cargo run 会d出一下对话框。

新版本的板条箱中再带了几个例子,可以在windows-rs项目仓库的examples目录。

总结

Rust for Windows 给rust在Windows开发应用带来了福音,虽然一些API可能早就被广泛地使用了,但是现在有了官方的支持,可以在文档、示例和稳定性等各方面都有极大的改善。

以上就是关于我为什么要选择Rust全部的内容,包括:我为什么要选择Rust、ps5可以玩rust吗、[from js to rust 系列][宏-01][官网文档 19.5]高级特性:宏[译文]等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/sjk/10170500.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存