rust垃圾场起重机怎么用

rust垃圾场起重机怎么用,第1张

Rust是一种系统级别的编程语言。Rust的垃圾回收机制是以内存安全模型为中心的。Rust的垃圾回收机制是手动的,因此需要开发人员自己负责管理内存,以确保内存释放正确。在Rust语言中,可以使用Box类型来管理内存。当对象不再使用时,可以使用drop()函数来释放对象所分配的内存。在以下情况下可以使用dro机制:需要跟踪对象的生命周期,需要在运行时控制内存管理。而用Rust实现垃圾场起重机,需要调用底层API来控制内存管理。因此需要开发人员具备系统级编程的技能。

特性对象中有一部分特性是自动特性,rust里的自动特性有Send Sync Unpin UnwindSafe RefUnwindSafe。

自动特性的自动就是说当代码在需要任何这五个特性的时候如果没有写上,编译器会根据一些规格给加上。其实也就是一些推导的过程,并不复杂。

当引用一个类型,引用可变类型,解构常量类型,解构可变类型,数组类型重复表达式中的类型,切片类型等这些类型实现了任意以上五个特性,这些类型就会自动具有这些特性。

函数项类型包括函数名称,类型参数,早期生命时间参数等能够标识这个函数的所有部分,以及泛型参数。

结构,枚举,联合,元祖类型只有所有的字段都实现了自动特性它们就具有自动特性。

闭包只有所有值和共享引用的类型实现了自动特性它就具有自动特性。

对于泛型如果类型参数实现Sync特性,编译器会为这个引用类型实现Send,如果类型是Send则编译器不会去实现Send。

自动特性可以有负实现,就是实现的时候在特性前面加上!号。意思就是类型实现了自动特性引用或者解构的可变及不可变反而是去除了这个自动特性。

1、首先修改LumaEmuini文件[Player]PlayerName=XXXX(此为你的游戏名自行修改)修改完保存它。
2、其次启动RustClientexe而不是rustexe。进入游戏界面调出控制台(F1)输入指令:netconnect127001:28015。
3、最后指令段式详解:netconnectip_adress:port。ip_adress为你的服务器IP地址port是端口,回车输等待连接即可。

rust防空需要20伏电力。根据查询相关公开信息,先进入游戏当中,点击鼠标左键就能查看rust防空的需要电量是20V。Rust是一门系统编程语言,专注于安全,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言。

Rust 是一种日益流行的编程语言,被视为硬件接口的最佳选择。通常会将其与 C 的抽象级别相比较。本文介绍了 Rust 如何通过多种方式处理按位运算,并提供了既安全又易于使用的解决方案。



在系统编程领域,你可能经常需要编写硬件驱动程序或直接与内存映射设备进行交互,而这些交互几乎总是通过硬件提供的内存映射寄存器来完成的。通常,你通过对某些固定宽度的数字类型进行按位运算来与这些寄存器进行交互。

例如,假设一个 8 位寄存器具有三个字段:

字段名称下方的数字规定了该字段在寄存器中使用的位。要启用该寄存器,你将写入值 1(以二进制表示为 0000_0001)来设置 Enabled 字段的位。但是,通常情况下,你也不想干扰寄存器中的现有配置。假设你要在设备上启用中断功能,但也要确保设备保持启用状态。为此,必须将 Interrupt 字段的值与 Enabled 字段的值结合起来。你可以通过按位 *** 作来做到这一点:

通过将 1 和 2(1 左移一位得到)进行“或”(|)运算得到二进制值 0000_0011 。你可以将其写入寄存器,使其保持启用状态,但也启用中断功能。

你的头脑中要记住很多事情,特别是当你要在一个完整的系统上和可能有数百个之多的寄存器打交道时。在实践上,你可以使用助记符来执行此 *** 作,助记符可跟踪字段在寄存器中的位置以及字段的宽度(即它的上边界是什么)

下面是这些助记符之一的示例。它们是 C 语言的宏,用右侧的代码替换它们的出现的地方。这是上面列出的寄存器的简写。& 的左侧是该字段的起始位置,而右侧则限制该字段所占的位:

然后,你可以使用这些来抽象化寄存器值的 *** 作,如下所示:

这就是现在的做法。实际上,这就是大多数驱动程序在 Linux 内核中的使用方式。

有没有更好的办法?如果能够基于对现代编程语言研究得出新的类型系统,就可能能够获得安全性和可表达性的好处。也就是说,如何使用更丰富、更具表现力的类型系统来使此过程更安全、更持久?

继续用上面的寄存器作为例子:

你想如何用 Rust 类型来表示它呢?

你将以类似的方式开始,为每个字段的偏移定义常量(即,距最低有效位有多远)及其掩码。掩码是一个值,其二进制表示形式可用于更新或读取寄存器内部的字段:

最后,你将使用一个 Register 类型,该类型会封装一个与你的寄存器宽度匹配的数字类型。 Register 具有 update 函数,可使用给定字段来更新寄存器:

使用 Rust,你可以使用数据结构来表示字段,将它们与特定的寄存器联系起来,并在与硬件交互时提供简洁明了的工效。这个例子使用了 Rust 提供的最基本的功能。无论如何,添加的结构都会减轻上述 C 示例中的某些晦涩的地方。现在,字段是个带有名字的事物,而不是从模糊的按位运算符派生而来的数字,并且寄存器是具有状态的类型 —— 这在硬件上多了一层抽象。

用 Rust 重写的第一个版本很好,但是并不理想。你必须记住要带上掩码和偏移量,并且要手工进行临时计算,这容易出错。人类不擅长精确且重复的任务 —— 我们往往会感到疲劳或失去专注力,这会导致错误。一次一个寄存器地手动记录掩码和偏移量几乎可以肯定会以糟糕的结局而告终。这是最好留给机器的任务。

其次,从结构上进行思考:如果有一种方法可以让字段的类型携带掩码和偏移信息呢?如果可以在编译时就发现硬件寄存器的访问和交互的实现代码中存在错误,而不是在运行时才发现,该怎么办?也许你可以依靠一种在编译时解决问题的常用策略,例如类型。

你可以使用 typenum 来修改前面的示例,该库在类型级别提供数字和算术。在这里,你将使用掩码和偏移量对 Field 类型进行参数化,使其可用于任何 Field 实例,而无需将其包括在调用处:

现在,当重新访问 Field 的构造函数时,你可以忽略掩码和偏移量参数,因为类型中包含该信息:

看起来不错,但是……如果你在给定的值是否适合该字段方面犯了错误,会发生什么?考虑一个简单的输入错误,你在其中放置了 10 而不是 1:

在上面的代码中,预期结果是什么?好吧,代码会将启用位设置为 0,因为 10&1 = 0。那真不幸;最好在尝试写入之前知道你要写入字段的值是否适合该字段。事实上,我认为截掉错误字段值的高位是一种 1未定义的行为(哈)。

如何以一般方式检查字段的值是否适合其规定的位置?需要更多类型级别的数字!

你可以在 Field 中添加 Width 参数,并使用它来验证给定的值是否适合该字段:

现在,只有给定值适合时,你才能构造一个 Field !否则,你将得到 None 信号,该信号指示发生了错误,而不是截掉该值的高位并静默写入意外的值。

但是请注意,这将在运行时环境中引发错误。但是,我们事先知道我们想写入的值,还记得吗?鉴于此,我们可以教编译器完全拒绝具有无效字段值的程序 —— 我们不必等到运行它!

这次,你将向 new 的新实现 new_checked 中添加一个特征绑定(where 子句),该函数要求输入值小于或等于给定字段用 Width 所能容纳的最大可能值:

只有拥有此属性的数字才实现此特征,因此,如果使用不适合的数字,它将无法编译。让我们看一看!

new_checked 将无法生成一个程序,因为该字段的值有错误的高位。你的输入错误不会在运行时环境中才爆炸,因为你永远无法获得一个可以运行的工件。

就使内存映射的硬件进行交互的安全性而言,你已经接近 Rust 的极致。但是,你在 C 的第一个示例中所写的内容比最终得到的一锅粥的类型参数更简洁。当你谈论潜在可能有数百甚至数千个寄存器时,这样做是否容易处理?

早些时候,我认为手工计算掩码有问题,但我又做了同样有问题的事情 —— 尽管是在类型级别。虽然使用这种方法很不错,但要达到编写任何代码的地步,则需要大量样板和手动转录(我在这里谈论的是类型的同义词)。

我们的团队想要像 TockOS mmio 寄存器 之类的东西,而以最少的手动转录生成类型安全的实现。我们得出的结果是一个宏,该宏生成必要的样板以获得类似 Tock 的 API 以及基于类型的边界检查。要使用它,请写下一些有关寄存器的信息,其字段、宽度和偏移量以及可选的 枚举 类的值(你应该为字段可能具有的值赋予“含义”):

由此,你可以生成寄存器和字段类型,如上例所示,其中索引:Width、Mask 和 Offset 是从一个字段定义的 WIDTH 和 OFFSET 部分的输入值派生的。另外,请注意,所有这些数字都是 “类型数字”;它们将直接进入你的 Field 定义!

生成的代码通过为寄存器及字段指定名称来为寄存器及其相关字段提供名称空间。这很绕口,看起来是这样的:

生成的 API 包含名义上期望的读取和写入的原语,以获取原始寄存器的值,但它也有办法获取单个字段的值、执行集合 *** 作以及确定是否设置了任何(或全部)位集合的方法。你可以阅读 完整生成的 API 上的文档。

将这些定义用于实际设备会是什么样?代码中是否会充斥着类型参数,从而掩盖了视图中的实际逻辑?

不会!通过使用类型同义词和类型推断,你实际上根本不必考虑程序的类型层面部分。你可以直接与硬件交互,并自动获得与边界相关的保证。

一旦到位,使用这些寄存器就像 read() 和 modify() 一样简单:

当我们使用运行时值时,我们使用如前所述的 选项 。这里我使用的是 unwrap,但是在一个输入未知的真实程序中,你可能想检查一下从新调用中返回的 某些东西 : 1 2

根据你的个人痛苦忍耐程度,你可能已经注意到这些错误几乎是无法理解的。看一下我所说的不那么微妙的提醒:

expected struct typenum::B0, found struct typenum::B1 部分是有意义的,但是 typenum::UInt<typenum::UInt, typenum::UInt 到底是什么呢?好吧,typenum 将数字表示为二进制 cons 单元!像这样的错误使 *** 作变得很困难,尤其是当你将多个这些类型级别的数字限制在狭窄的范围内时,你很难知道它在说哪个数字。当然,除非你一眼就能将巴洛克式二进制表示形式转换为十进制表示形式。

在第 U100 次试图从这个混乱中破译出某些含义之后,我们的一个队友简直《 疯了,地狱了,不要再忍受了(Mad As Hell And Wasn’t Going To Take It Anymore)》,并做了一个小工具 tnfilt,从这种命名空间的二进制 cons 单元的痛苦中解脱出来。tnfilt 将 cons 单元格式的表示法替换为可让人看懂的十进制数字。我们认为其他人也会遇到类似的困难,所以我们分享了 tnfilt 。你可以像这样使用它:

它将上面的输出转换为如下所示:

现在这才有意义!

当在软件与硬件进行交互时,普遍使用内存映射寄存器,并且有无数种方法来描述这些交互,每种方法在易用性和安全性上都有不同的权衡。我们发现使用类型级编程来取得内存映射寄存器交互的编译时检查可以为我们提供制作更安全软件的必要信息。该代码可在 bounded-registers crate(Rust 包)中找到。

我们的团队从安全性较高的一面开始,然后尝试找出如何将易用性滑块移近易用端。从这些雄心壮志中,“边界寄存器”就诞生了,我们在 Auxon 公司的冒险中遇到内存映射设备的任何时候都可以使用它。

此内容最初发布在 Auxon Engineering 博客 上,并经许可进行编辑和重新发布。

via: >

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

原文地址: https://outofmemory.cn/dianzi/12999852.html

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

发表评论

登录后才能评论

评论列表(0条)

保存