一位 JavaScript 铁杆粉眼中的 Rust

2023-05-16

  以下为译文:

  我使用 Rust 编写了一些小工具,而且觉得很有乐趣。我的日常工作需要大量使用 JavaScript,而 Rust 给我一种非常熟悉的感觉,因此我决定尝试一下Rust。但与此同时,使用 Rust 完成真正有意义的工作需要重新思考代码的结构和合理性。编译器是最公正无私的,然而反复修改代码,直到最终通过编译也是一种乐趣。

  在这篇文章中,我将分享我在 Rust 之旅中的一些想法,以及作为 JavaScript 铁杆粉,我对 Rust 的看法。

  

  现代 Rust“看起来”与现代 JavaScript 非常相似。你可以使用 let 声明变量,而且函数看上去也很相似,由于 TypeScript 的流行,我对 Rust 的类型也不陌生,还有 async/await,总的来说,我对 Rust 有一种莫名的熟悉感。

  问题的核心不是语法,而是 Rust 对程序内部结构的推理方式。高级语言中包含大量抽象,因此你不必担心计算机的工作方式。这非常合情合理,如果你的目标是开车赶到办公室,那么只需要知道如何驾驶汽车,而不必搞懂内燃机的内部结构。相比之下,在低级语言中,你会得到螺栓和螺丝钉,为了开车去超市,你必须成为一名汽车修理工。

  每种方法都有各自的优缺点,因此,它们的主要问题领域也不同。而 Rust 的目标是中间地带。你既可以使用 Rust 访问基础设施,也可以使用清晰易懂的高级抽象。但是,开发人员势必会为此付出代价:你必须学习一种新的程序推理方式。

  

  计算机程序依赖内存中的读写。内存读写是不可避免的,就像巧妇难为无米之炊。做饭的时候,我们必须将食材都买回来,然后洗干净切好,再按照正确的顺序将它们放入锅中,吃完饭后还需要收拾厨房里的烂摊子。

  而高级语言提供了垃圾收集器,就像我们的父母,他们会耐心地帮你打扫卫生,而你则无需弄脏双手。然而,Rust 的内存管理是:“嗯……真正的厨师会清理自己的垃圾”。这也并非全无道理,因为垃圾收集器本身就有很深奥的问题,而且会带来意料之外的结果。但与此同时,Rust 借鉴了其他语言的过往经验,并强制程序员管理好内存。

  

  在 Rust 中,变量只能在某个作用域内使用。如果这个作用域不再有效,则这块内存就会返回给系统。编译器会向在代码中注入一段代码来确保这一点。这在 Rust 中是铁一样的定律。

  下面,我们来看一个示例

  

  这段代码有两个作用域。一个外层作用域来自 main,还有一个内层作用域。Rust 的所有权如下:

  main 拥有 a 和 b;

  a 想要使用内层作用域,所以 main 将 a 的所有权转移到内层;

  内层作用域处理a,然后完成;

  Rust的隐藏代码丢弃 a 的作用域;

  main 处理 b,然后完成;

  Rust 丢弃 b 的作用域。

  请注意,所有权都会还给系统,而不是作用域的起源。a 的所有权不会返回给main 作用域。

  等一等,这种做法听起来很危险。如果遇到如下代码,该怎么办?

  

  在这段代码中,main 作用域想再次使用 a,但是我们说当内层作用域结束时,Rust 已经删除了 a。

  程序执行到这里的时候,不会崩溃吗?

  没错,程序会崩溃。

  

  Rust 编译器会彻查一切,并评估程序是否可以安全运行。只有通过所有的检查,它才会生成可执行文件。

  

  在上面这个例子中,编译器拒绝提供二进制文件。

  程序员的职责是了解 Rust 的法则,并遵守这些法则。包括这门语言所有的细节,所有的怪癖,所有的假设。否则,Rust 编译器就会冲我们大吼大叫。另一方面,Rust 团队一直在努力通过创建大量语法糖和清晰的错误消息,帮助我们理解错误。而且,Rust 还有非常完善的文档和一个伟大的社区。

  

  在 Rust 大陆中,变量是玩家。玩家必须属于某个职业:法师、牧师、结构体。此外,每个玩家可能拥有不同的装备。当然,你可以拥有两个牧师,一个拿着权杖,一个拿着魔杖。

  还记得上述代码中的dbg!吗?这是一个宏,相当于 JavaScript 的 console.log。下面,我们来创建一个有类型的变量,并输出日志。

  

  我们创建了一个 struct,本质上是一个类型。然后我们又创建了一个该类型的对象。最后,我们输出该对象。

  

  以上,Noob 类型的 player 连调试信息都没有……

  关键在于,我们手动创建的变量都是从 1 级开始的,没有装备。这里需要装备(用 Rust的术语说,就是 traits)。

  我们来修改一下。

  

  这一次可以了。唯一的不同就在于开头的第一行。我们为 Noob 配备了 Debug 特性。现在,我们的player就有资格输出日志了。巨大的进步!

  Rust 拥有大量的装备,比其他语言更普遍。而且,你还可以自己设计并打造新装备。

  有些 trait 可以由编译器为我们自动生成。而有些则需要自己实现。你想给你的法师打造一个盔甲?没问题,当然可以,但是你必须提供实际的代码。

  trait 在 Rust 的结构中根深蒂固。我们再来看一看上述那个报错的例子。仔细阅读错误消息,我们会注意到,编译器向我们解释,必须“移动”变量的所有权,因为字符串没有实现 trait:Copy。

  Copy trait 意味着你可以获取一段内存,然后 memcpy 到其他地方,直接对字节进行操作。

  那么,既然字符串没有 Copy trait,我们可不可以要求编译器提供一个?抱歉,不行。Copy 的级别太低,字符串无法安全地使用这个trait。编译器知道这一点,所以不提供。当然,如果故事就此结束,Rust 就不会成为一门非常实用的语言了。实际上,字符串有一个更明确的 trait,可以完成相同的工作:Clone。而字符串也具有 Clone trait,因此我们只能用 Clone 来代替 Copy。

  我们来稍微调整一下代码,像下面这样:

  

  在这段代码中,编译器看到我们想在内层作用域中使用a,而且它看到我们可以使用 clone 来完成操作。所以,

  a 的所有权归 main;

  a.clone 在创建后,被借用到内层作用域;

  内层作用域执行操作,然后完成;

  Rust 丢弃 a.clone 的作用域;

  main 可以使用 a,因为 a 的所有权始终归它所有。

  当然,这不是唯一解决这个问题的方法,但我们可以通过这个例子初步探索一下所有权和trait。

  

  文本介绍的内容对于 Rust 学习来说,不过是冰山一角。根据我的个人经历,Rust 的学习曲线很陡峭,但整个学习过程很有趣,而且物有所值!我会继续努力学习下去!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一位 JavaScript 铁杆粉眼中的 Rust 的相关文章

随机推荐

  • 移动立方体算法(MC)

    该算法的基本思想是在体数据的每一个立方体单元中根据其八个顶点的数据值与给定数据值的关系在单元的12条边上寻找等值点 xff0c 然后用三角形将等指点连成等直面 MC算法对感兴趣的等值面可以产生清晰的图像 xff0c 但是提取的轮廓存在二义性
  • WebSocket 前端 Vue 长连接 断线重连

    文章目录 WebSocket简介额外注意点 实际开发代码创建WebSocket工具文件创建WebSocket连接初始化WebSocket心跳防止断开连接收到信息后区分业务信息和心跳信息定义关闭连接的方法 xff0c 方便登出时使用将关闭和创
  • CentOS7下安装mysql5.7

    更多精彩技术分享请浏览本人博客 xff1a https blog csdn net wohiusdashi 一 安装YUM Repo 1 由于CentOS 的yum源中没有mysql xff0c 需要到mysql的官网下载yum repo配
  • VSCode 安装 Go 插件、gopls 是个什么东东

    原文地址 xff1a VSCode 开发 Go 程序也可以和 GoLand 一样强大 VSCode 建议你启用 gopls xff0c 它到底是个什么东东 xff1f
  • RPC 笔记(05)— socket 通信(单线程服务器)

    1 Python 标准库 1 1 socket 提供 RPC 服务的网络通信功能 xff0c 方便用户编写 tcp udp 相关的代码 两个不同机器的进程需要通信时 xff0c 可以通过 socket 来传输数据 客户端 API xff0c
  • ubuntu的文件系统结构

    一 ubuntu 系统的根目录 Linux 系统下 就是系统的根目录 xff0c 所有的目录是由根目录衍生出来的 进入根目录的方法 xff1a 终端输入 34 cd 34 命令 如下所示 xff1a 二 ubuntu 文件系统结构 bin
  • 八、安装go-cqhttp+QQBot教程+对接青龙

    首先要有一台云服务器 阿里云 点击跳转 腾讯云 点击跳转 QQ交流群 244016111 上车 点击跳转 或 关注公众号 汤姆的日记 已更新全套需要点击跳转 一 服务器基础设置及宝塔 43 docker安装教程 二 青龙面板安装教程 43
  • c语言中d和i有什么区别

    c语言中d和i的区别 xff1a 在 printf 格式串中使用时 xff0c 没有区别 在 scanf 格式串中使用时 xff0c 有点区别 xff0c 如下 xff1a 在scanf格式中 xff0c d 只与十进制形式的整数相匹配 而
  • CentOS7.2 安装GitLab服务器

    01 yum install y curl policycoreutils python openssh server 02 systemctl enable sshd 03 systemctl start sshd 04 wget htt
  • STM32CubeMX生成STM32L073RZT6 BootLoader程序

    1 环境 xff1a Windows10 xff0c STM32CubeMX6 0 0 xff0c Keil5 25 单片机为STM32LRZT6 196KBytes Flash xff0c 20KBytes RAM 2 功能要求 设计Bo
  • RHEL7 的注册

    安装RHEL7后 xff0c 在没有注册的时候 xff0c YUM软件仓库是不能使用的 xff0c 需要注册后才可以使用 xff0c 但是RHEL是商用版系统 xff0c 需要购买授权 在网上查找后 xff0c 发现RHEL有个开发者订阅
  • linux下查看可执行文件的相关信息

    1 file 可执行文件 可查看可执行文件是ARM架构还是X86架构 2 nm 可执行文件 可查看文件中的符号 xff0c 包括全局变量 xff0c 全局函数等 3 ldd 可执行文件 可查看文件执行所需要的动态库 4 strings 可执
  • linux下查看系统内存使用情况的几个命令

    最近在客户现场运行的arm linux嵌入式设备出现了死机情况 xff0c 由于接触linux嵌入式设备时间不长 xff0c 遇到该问题后觉得束手无措 后领导提示说查看其他没有死机设备的系统资源使用情况 xff0c 下面介绍下我用到的那些命
  • Linux下获取CPUID、硬盘序列号

    在很多系统软件的开发中 xff0c 需要使用一些系统的唯一性信息 所以 xff0c 得到主机的CPUID 硬盘序列号及网卡的MAC地址 xff0c 就成个一件很重要的应用 需要的准备知识有 xff1a 1 GCC的嵌入汇编 xff0c 具体
  • Thinkpad MORFFHL滑鼠接收器配对

    1 接收器插入电脑 2 关闭鼠标 3 同时按住鼠标左键 右键 滚轮打开电源开关 xff0c 3个键按住3秒左右松手 4 同时按下3个按键 xff0c 指示灯橘色闪烁 5 再次同时按下3个按键 xff0c 配对结束 6 关闭鼠标重新打开 移动
  • Vbox6.04 Debian虚拟机安装增强工具

    环境 xff1a VBox6 04 Debian9 6 64位 在创建Vbox虚拟机后安装好Debian系统 开始操作前请确保虚拟机可以上网 1 root用户登录Debian xff1b 2 uname r 查看debian内核版本 3 a
  • Debian系统源码安装usb网卡驱动

    系统为debian 9 6 64位版本 xff0c 安装网卡驱动为asix的 AX88772B芯片 1 安装系统build模块 apt get install linux image uname r linux headers uname
  • Ubuntu根目录下各文件夹的作用

    Ubuntu上常识和常用命令 xff1a 1 Ubuntu文件结构 在ubuntu上硬盘的目录和Windows上不同 xff0c Windows可以根据自己的需求分不同的盘符 xff0c 但ubuntu上只有一个盘 xff0c 从根目录开始
  • linux中的export命令介绍

    export Linux中export命令介绍 xff0c 三种方法设置环境变量 CSDN博客
  • 一位 JavaScript 铁杆粉眼中的 Rust

    以下为译文 xff1a 我使用 Rust 编写了一些小工具 xff0c 而且觉得很有乐趣 我的日常工作需要大量使用 JavaScript xff0c 而 Rust 给我一种非常熟悉的感觉 xff0c 因此我决定尝试一下Rust 但与此同时