仍然没有问题。

上次查看Rust的所有权时,我们查看了Rust如何使用范围来确定何时应该删除或释放内存中的资源/数据。

我们看到,对于具有"复制特征"的类型(即,其数据可以存储在堆栈中的类型),所有权模型的行为类似于可能使用不同范式的其他语言,例如垃圾回收。 但是对于没有这种特征的类型,我们需要更加了解所有权规则。

尽管所有权可能会带来一些设计折衷,但它会以灵活性,明确性和安全性来弥补。

所有权和职能

> Copy versus Move

在第一个示例中,我们首先将字符串文字(将其数据存储在堆栈中)传递到函数foo()中。 在第二个示例中,我们将String类型(将数据存储在堆中)传递给另一个函数foo()。 在main()和foo()的两种实现中,我们都在各自的作用域中打印变量的内存地址。

在第一个示例中,我们看到了与复制变量的值并将其绑定到新变量时类似的行为。 发生这种情况是因为字符串文字使用了堆栈。 存储它们的指针所需的大小在编译时就已知道,因此,我们可以轻松地复制它的值并将其弹出到堆栈中。

这意味着每个函数main()和foo()都拥有存储在字符串中的指针的副本。 当foo()的作用域结束时,foo()负责删除其自己的字符串,当main()的作用域结束时,它也负责删除其拥有的字符串。

另一方面,在第二个示例中,main()将字符串的所有权移到foo()中。 这意味着main()不再拥有字符串变量的所有权,即它指向的内存位置。 如果在移动main()之后尝试从内部访问字符串,则会收到错误消息。

如示例注释所示,Rust代替了复制(这可能会很昂贵),而是让foo()负责内存地址0x7efced01c010中的数据。 现在,只有当foo()超出范围时,Rust才会释放该地址处的内存,从而使具有指向该地址的指针的其他任何变量无效。 再次,我们这样做是为了避免双重释放错误。

克隆,redux。

对于第二个示例,如果我们确实想复制string的值,以便main()和foo()都拥有自己的副本,类似于在堆栈上使用字符串文字时,我们可以进行"深层复制" ,通过使用clone()方法:

> clone()

在这里,如注释所示,main()和foo()拥有各自的字符串副本的所有权。 尽管这是一个有效的解决方案,但它并不是最有效的,因为Rust每次都需要逐步完成其堆分配过程。 有时您实际上确实希望两个函数都与同一数据交互! (稍后会详细介绍)。

赋予所有权

就像通过调用另一个函数并传入变量来获取所有权一样,可以通过从其他函数返回来为函数赋予所有权:

> Giving ownership

现在,foo()通过将字符串返回到调用foo()的位置来赋予main()所有权。 不出所料,只有当main()的作用域结束时,Rust才会释放0x7fc98be1c010。

给予与接受

如果我们遵循这种趋势,那么我们既可以赋予所有权,又可以通过接受并在foo()中返回相同的String类型来将所有权归还给我们,这是有意义的:

> Passing ownership

但这仅仅是为了将值传入和传出函数而感到头疼。 幸运的是,Rust维护者已经考虑到了这令人头疼:

拥有所有权然后返回所有功能的所有权有点乏味。 如果我们想让函数使用值而不是所有权怎么办? 很烦人的是,除了我们可能还想返回的函数主体产生的任何数据之外,如果我们想再次使用它,也需要将返回的信息传递回去。 对我们来说幸运的是,Rust具有此概念的功能,称为参考。

—Rust书

应用和借用

所有权可以容纳数据的共享和传递,但是您必须遵循一些规则。

借用看起来像这样:

main()使foo()可以访问字符串,但是,(如标签所示)main()仍然是字符串的所有者。 这意味着在foo()作用域的末尾,不会从内存中删除字符串。 main()仍然负责字符串在内存中的空间。

这是我们如何在Rust中编写交互的方法:

> Passing a reference/borrowing

就像我们的绘图一样,我们可以说main()将字符串的引用传递到foo()和foo()中,除了String类型引用。 用&符号表示。 在foo()的作用域结束之后,执行返回到其调用方main(),并且字符串仍然有效。 foo()不必归还所有权,因为它从未被授予所有权,它只是借来的。

"&"号表示引用,这些引用允许在不放弃所有权的情况下传递值! Rust知道,当我们传递引用时,所有权以及因此在内存中分配该空间的责任仍然属于原始所有者。

Rust允许我们创建任意数量的引用:

> Passing multiple references of the same value

无论我们传递多少次对字符串的引用,所有权都会恢复为其原始所有者。 (在这种情况下,所有权返回到最初实例化字符串的位置,但是请记住,我们可以传递所有权然后创建一个引用)。

可变性

最后要提到的是可变性。 Rust通常是以实用的风格编写的,但作者非常务实,并了解现代语言并不总是如此黑白,因此Rust可以适应可变性。

> mut

Rust允许我们使用mut关键字来使值可变。 注意内存地址的更改,该更改指示必须重新分配字符串才能适合堆。

现在我们有了一个可变变量,我们就可以进行可变引用了!

> Passing a mutable reference

这里的语法有点特定,但是我们看到首先需要声明一个可变变量let mut string。 然后,当我们使用&mut传递可变的引用时。 最后,我们在函数的签名中使用&mut来明确声明我们的函数接受可变引用。

现在,我们仍然可以确保只负责main()负责字符串的解除分配,同时还允许其他函数对字符串进行突变!

那些熟悉内存管理的人可能会想到,如果不加以检查,这将是多么危险。 如果多个函数持有一个可变的引用并尝试异步地同时更新同一内存位置,将会发生什么情况? 例如在使用线程时? 这导致数据争用情况。

当两个或多个线程可以访问共享数据并且它们试图同时更改它们时,就会发生竞争状态。由于线程调度算法可以随时在线程之间交换,因此您不知道线程尝试访问共享数据的顺序。因此,数据更改的结果取决于线程调度算法,即两个线程都在“竞争”访问/更改数据。

— Lehane和Amit Joki通过SO

当使用低级语言(例如Rust)时,此问题可能会加剧。 Rust允许我们访问原始指针,这可能会导致很多不安全的情况发生。

这是所有权要保护的一种事物,它通过执行以下规则来做到这一点:"在任何给定时间,您可以拥有一个可变引用或任意数量的不可变引用。"

具有此限制的好处是Rust可以防止在编译时发生数据争用。 数据争用类似于争用条件,并且在以下三种行为发生时发生:

-两个或多个指针同时访问相同的数据。

-至少有一个指针用于写入数据。

-没有用于同步数据访问的机制。

数据争用会导致未定义的行为,并且在尝试在运行时进行跟踪时可能会难以诊断和修复; Rust不会发生此问题,因为它甚至不会通过数据竞争来编译代码!

—Rust书

Rust的所有权规则再次得以解决,这被强调为Rust在其他系统语言之上提供的核心安全功能。 这意味着Ruby程序员和我一样,仍然不必熟悉内存管理的内部工作!

悬挂引用

最后一件事,当传递引用时,还有另一种情况会导致错误,称为悬挂引用。

悬挂引用是指向已释放数据的指针,例如:

> Dangling Reference — WILL NOT COMPILE!

在此示例中,foo()返回对字符串的引用。 但是,一旦foo()的作用域结束,便会释放字符串的内存,这意味着引用将指向内存中的无效位置!

Rust在编译时通过抛出错误来防止这种情况。

类可以享受所有权模型的好处,而无需了解其提供的保护。 但是,能够理解所有权只能解决的问题有助于编写更好的代码,而无需与编译器抗争。

关于Rust的所有权还有更多的东西要揭露,但是有了这两篇文章,希望您有足够的机会开始使用这种优雅的解决方案来解决原本难以解决的问题。

参考资料

· Rust书

· 关于复制特性的Rust语言表单帖子

(本文翻译自Thomas Countz的文章《Ownership in Rust, Part 2》,参考:https://medium.com/@thomascountz/ownership-in-rust-part-2-c3e1da89956e)

rust实现wss访问_Rust的所有权,第2部分相关推荐

  1. rust实现wss访问_改进 JavaScript 和 Rust 的互操作性并深入认识 wasm-bindgen 组件

    前言 最近我们已经见识了WebAssembly如何快速编译.加速JS库以及生成更小的二进制格式.我们甚至为Rust和JavaScript社区以及其他Web编程语言之间的更好的互操作性制定了高级规划.正 ...

  2. java netty wss_netty 配置 wss访问

    # netty 配置 wss访问 ## 1.获取证书 可以选择[自制证书](生成自签名证书.md),或者获取 [Let`s Encrypt证书](LetsEncrypt.md) ## 2.配置hand ...

  3. webSocket配置wss访问

    通常我们都是使用ws访问websockert的,但是在https下访问的话,会报以下的错. 这个时候我们需要服务端开启wss访问,直接上代码,在nginx配置server里面加上以下代码,端口号为we ...

  4. 里rust怎么找蓝图_Rust错误处理

    错误处理是程序开发中必不可少的一个环节,在Rust中,错误分成两个类别:可恢复错误和不可恢复错误. 可恢复错误:比如说未找到文件,Rust中用Result<T,E>来实现 不可恢复错误:比 ...

  5. rust废铁最快_Rust初体验,它确实有点快

    写了多年的Java,某天机缘巧合之下听说了一门语言叫Rust,Rust的亲爹是Mozilla,如果要和其它语言拼爹的话,实力应该还是可以的. 官方介绍如下:Rust is blazingly fast ...

  6. Nginx配置wss访问实现微信小程序的websocket通信

    WSS是Web Socket Secure的简称, 它是WebSocket的加密版本.WSS与WS类似于HTTPS和HTTP,不同之处在于是不同的通信协议,都运行在SSL(Secure Socket ...

  7. rust拆除拆除指令_Rust 输出到命令行

    Rust 输出到命令行 在正式学习 Rust 语言以前,我们需要先学会怎样输出一段文字到命令行,这几乎是学习每一门语言之前必备的技能,因为输出到命令行几乎是语言学习阶段程序表达结果的唯一方式. 在之前 ...

  8. rust建造一键升级_rust 使用国内镜像,快速安装方法

    前言 众所周知的,国内由于防火墙的原因,访问国外的网络比较慢. 如果直接按照rust官网的安装方式安装非常容易失败,即使不失败也非常非常慢 如果用国内的镜像则可以分分钟就搞定 官方安装方法 curl ...

  9. Nginx配置域名反向代理MQTT 配置mqtt /ws /wss访问域名连接。

    有时候我们想通过域名的方式来进行mqtt的连接. 首先在阿里云上安装mqtt服务器端.本文mqtt服务器端ip地址为: xx.xx.67.177 并配置mqtt监听端口 tcp : 1883 , ht ...

最新文章

  1. 用Python和OpenCV创建一个图片搜索引擎的完整指南
  2. matlab如何创建table,MATLAB table数据结构 首篇
  3. 牛客练习赛71E-神奇的迷宫【点分治,NTT】
  4. 算法解题方法:求和问题preSum方法
  5. 第5课 混合编程和芯片手册阅读
  6. 常见笔顺错误的字_孩子的字越写越差,强行矫正效果差,家长应这样培养孩子书写态度...
  7. ubb php论坛程序,论坛UBB代码 推荐
  8. 杭州一般纳税人和小规模纳税人的区别
  9. 8 个顶级网络攻击地图以及如何使用它们
  10. 下载 .m3u8视频文件
  11. JAVA 获取文件指纹
  12. 将VSCode设置成中文
  13. ListView演练 - 带有组头的汽车品牌展示
  14. 最值得用的五款 chrome 插件 Vimium momentum The Great Suspender等 附下载地址。
  15. Android +kotlin Banner 轮播广告 获取后台数据
  16. 【c/c++编程】数学类问题:同余模、最大公约数、最小公倍数、素数判定
  17. layui表格点击按钮下方新增加空白行
  18. 单片机并行I/O口(P0)硬件结构
  19. Mongodb访问控制
  20. linux 添加开机动画,如何更改linux 开机画面?

热门文章

  1. 企业巧妙运用飞秋提高工作效率
  2. 六大加密工具让数据传送安然无恙
  3. C++字符串完全指引之一(Win32 字符编码)
  4. 为什么我们的软件不及印度
  5. 我是如何走上前端开发这条路 并常年保持一线竞争力的
  6. arcgis不闭合线转面_【干货】ArcGIS矢量面转点、点转面,面矢量转点矢量方法讲解,值得学习!...
  7. 打印机乱码不停打印_关于东芝复合机连接打印,图文教你如何轻松连接至电脑...
  8. githup用户名密码怎么看_MacBook Pro 开机密码忘记解决方法
  9. Option键竟然如此强大,99.9%的Mac用户不知道的高效秘技
  10. 第48课 加加乐 《小学生C++趣味编程》