我作为TypeScript开发人员是如何学习Rust的

讲讲我作为TypeScript开发人员学习Rust的经验吧,希望对你有帮助

像许多开发人员一样,我通过专注于网络技术开始了我的编程生涯。我相信这是一个很好的起点,JavaScript,互联网的语言,以及许多,是一个令人难以置信的多才多艺的选择。

随着我对JavaScript等高级语言的经验越来越丰富,我也对它们的工作原理越来越感兴趣:它们正在做出哪些选择和权衡,以及更高层次的抽象的好处和成本是什么。

对我来说,更深入理解的最好方法之一是学习低级编程语言。毕竟,这些是通常解析和解释我们的JavaScript代码的语言。例如,V8引擎(由Google Chrome和Node.js使用)和WebKit(由Safari和Bun使用)都是用C++编写的。但是,尽管C++是低级编程的中流砥柱,但C++不是我选择的语言......

在伟大的低级编程语言中,Rust对我来说是最令人兴奋的。去年,Rust连续第八年成为Stack Overflow年度调查中最受赞赏的编程语言。

该语言承诺在与C和C++相同的联盟中运行时性能,但具有严格的类型系统、许多内存安全功能和更主动的错误处理方法------因此您可以避免垃圾收集器的开销,避免内存泄漏的风险,而内存泄漏在C等语言中更容易创建。

Rust用途广泛,具有面向对象和函数式编程的范式,连续第三年,它一直是Web汇编中最受欢迎的语言,甚至已成为Linux内核中的重要语言。Rust也在JavaScript领域掀起波澜,在那里它一直被用来构建重要项目,如Deno,以及最近的LLRT(亚马逊无服务器函数的低延迟运行时)。

如何学习Rust

与任何其他编程语言一样,我认为学习Rust的最佳方式是尝试用该语言编程一些东西。

然而,Rust的初始学习曲线似乎比我近年来尝试过的其他语言更陡峭,所以在开始使用该语言之前,值得花更长的时间浏览入门材料。

Rust组织的网站有很好的建议。现在,这些是The Book、Rustlings课程和Rust by Example。我还推荐Rust by Practice,这是一个类似于Rustlings的互动课程。

在YouTube上,NoBoilerplate频道帮助我对这种语言感到兴奋,并且是解释一般Rust概念的绝佳来源。如果您对托管Rust感兴趣,AWS有一篇关于在其平台上增加对Rust支持的博客文章。

本文的其余部分不是Rust的初学者指南。如果这就是你要找的,我建议你点击上面的链接。相反,与我每天专业使用的语言TypeScript相比,我分享了开发人员使用Rust体验的一些最显著差异的想法。

编译器

Rust编译器经常被引用为Rust最好的部分之一,然而,对于初学者来说,它也可能感觉是最令人讨厌的部分之一!

来自TypeScript,我惊讶于编译器在多大程度上改变了编码体验。像许多开发人员一样,我通常会避开适当的调试工具,而倾向于自由记录值。但在Rust中,只有当编译器满意时,您才能记录值。

在某些情况下,这被证明是令人沮丧的:例如,在为反序列化步骤编写严格类型之前,我想记录一个请求的JSON有效负载。(后来,我了解到这可以用theserdeserde_json::Value类型来完成)。

但一般来说,努力满足编译器意味着,通常,当我运行代码时,它会按照我的预期工作。这里的权衡似乎很清楚。至少对于初学者来说,运行代码确实需要更长的时间,但当该代码确实运行时,它更安全、更可预测、性能更高。你在写作阶段投入了更多的工作,但出现错误或性能记忆问题的几率似乎更低------在大型、不断增长的项目中,这些好处感觉越来越重要。

来自错误消息不太有用的语言的开发人员可能会发现,他们已经准备好快速扫描错误。但到目前为止,我发现Rust编译器错误非常好,经常确切地告诉你需要做什么才能运行代码------我对语言及其类型越有经验,我就越能理解编译器试图告诉我什么!

类型系统

我知道不是每个JavaScript开发人员都喜欢TypeScript------例如,请参阅这篇(不)著名的博客文章------但我无法想象在没有类型的情况下编写大型JavaScript应用程序。然而,TypeScript有其弱点,我认识到拥有一种类型为一流公民的语言有很多好处。Rust的类型系统经常被誉为其最佳功能之一。

也就是说,Rust的类型系统对我来说是新的部分不是Rust独有的,而是几乎所有低级语言的特征。例如,像其他低级语言一样,Rust允许我们非常具体地说明我们希望变量占用多少内存空间。如果我们知道一个数值将始终是0到255之间的整数,我们可以将其分配给长度为8位的u8。或者,如果我们的数字可以高于255,但我们知道是否会低于65,535,那么我们可以将其分配给16位u16类型,等等。

然而,在某些方面,Rust确实比其他低级语言走得更远。例如,它提供了至少八种字符串类型,而不是C的一个char\[\]类型,这有助于我们避免脚枪。(尽管如此,不要害怕,因为大多数用例都由&str和String覆盖!)

当然,TypeScript没有提供接近这种粒度水平的地方,因为根据设计,JavaScript不希望我们担心内存管理,因此为我们分配内存。这为我们节省了一份工作,但效率较低,因为JavaScript引擎必须在程序运行时动态分配内存。在小规模上,这没有什么区别。但在大型应用程序中,更高效和有目的的内存分配可以使程序占用更少的内存占用空间。

内存分配

在TypeScript中,我们在Javascript(一种不读取我们类型的语言)之上叠加类型注释,每当构建TypeScript代码时,它们都会被删除。

在Rust中,与其他类型为一流公民的语言一样,类型注释不仅仅是注释,它为该特定类型分配内存,并向我们保证该值将具有给定类型。

例如,如果我们将i8类型传递给下面的parse方法,它为small_int保留了8位内存。

复制代码
复制代码

let small_int = "127".parse::<i8>().unwrap();

parse方法甚至可以从变量类型中推断类型,因此我们也可以编写:

复制代码
复制代码

let small_int: i8 = "127".parse().unwrap();

在这种情况下,如果我们试图超越给定类型允许的内存,编译器也会对我们大喊大叫。因此,如果我们尝试将字符串"128"解析为i8,我们将无法编译。

比较TypeScript,其中类型标记只是标记。它们不会更改底层类型或分配的内存。下面,TypeScript期望x是一个字符串。但在底层的JavaScript中,它将是一个数字。

复制代码
复制代码

const x = 10 像字符串一样未知;

这个例子对TypeScript编译器有点不公平;我们正在使用unknown作为转义舱口来强行分配错误的类型!

然而,这是一个很容易抓住的简单例子。在现实世界的应用程序中,当处理更复杂的数据类型或从第三方获取的数据时,TypeScript更容易歪曲现实。

错误处理

让我们再次以将字符串转换为整数为例。这一次,让我们想象一下我们的整数是由用户提供的字符串,因此我们无法再保证我们可以正确解析它。

复制代码
复制代码

let parsed_int = submitted_str.parse::<i32>().unwrap();

在这里,我们使用unwrap来获得成功解析的值。但这种方法通常不鼓励。相反,Rust为我们提供了Result枚举,这迫使我们手动处理错误。

We can still cause our program to panic with thepanic!macro, but we can pass a custom error message which will help us quickly understand what went wrong:

添加图片注释,不超过 140 字(可选)

或者我们可以返回一个默认值------在这种情况下是0:

添加图片注释,不超过 140 字(可选)

还有一个简写方法:unwrap_or_default。

当然,这种行为在JavaScript中是可能的,但区别在于,在JavaScript中,您必须选择加入,而在Rust中,您必须使用unwrap来选择退出。

或者,换句话说,在JavaScript中,你必须有意识地处理错误。而在Rust中,你被迫要么处理错误,要么有意识地决定你只关心成功的道路。

可选值

Rust使用类似的方法来处理可选值。在TypeScript中,我们可以使用方便的?指示一个值可能undefined。

添加图片注释,不超过 140 字(可选)

这个TypeScript代码将毫无问题地编译,即使我们有返回我们不想要的东西的风险!

但是,如果我们使用Option在Rust中编写类似的东西,我们会收到一个编译时错误。

添加图片注释,不超过 140 字(可选)

The code above warns us that we cannot useOptioninside ourformat!macro --- preventing us from returning something unexpected. Instead, we are forced to handle this possibility. Here's one solution, usingmatch:

添加图片注释,不超过 140 字(可选)

再一次,这在TypeScript中是可以实现的------而且它更简洁。但两种语言之间的关键区别在于,在TypeScript中,开发人员有需要识别潜在的问题,因此我们最终不会返回"Hello undefined"但在Rust中,除非我们处理名称不可用的情况,否则我们的代码将无法编译。

在这样的简单例子中,很难认识到更冗长的方法的好处,因为很容易看出可能会出错什么。但是,如果您曾经开发过大型应用程序,很明显,Rust的选择退出方法可以使我们免于许多潜在的事故。

所有权和借贷

最后,我想谈谈所有权和借贷,这些概念在像Rust这样的低级语言中比像TypeScript这样的高级语言更有意义。

在TypeScript中,我们需要意识到我们是突变值还是克隆值。

添加图片注释,不超过 140 字(可选)

在上面的TypeScript代码中,sort将数组原位突变,更改原始值。但toSorted创建一个克隆,我们可以将其分配给一个新的变量,并保持原始数组不变。

一般来说,像toSorted这样的非破坏性方法在TypeScript等语言中通常是首选,因为跟踪突变变量可能很棘手,除非对内存或性能有明显的好处,否则通常认为最好完全避免这样做。

然而,Rust允许我们更深入地了解突变或克隆值,其好处是,一旦值实现其光荣的目的,我们可以更有效地使用内存,也可以更轻松地释放内存。

首先,默认情况下,所有变量都是不可变的,并且必须使用mut关键字明确标记为可变。

此代码抛出一个错误:

复制代码
复制代码

让foo = 10; foo += 10;

此代码不:

复制代码
复制代码

让mut foo = 10; foo += 10;

这感觉大致等同于JavaScript中的let与const。胸围锈走得更远。

例如,在JavaScript中,某些变量类型,如数组,总是可变的。即使我们使用const实例化它们,我们也可以push、pop和重新分配索引。在Rust中,我们需要mut才能做到这一点:

复制代码
复制代码

let mut nums: Vec<i32> = vec!1,2,3,4,5; nums.push(6);

Rust还允许我们将值的所有权从一个变量转移到另一个变量。以以下为例:

复制代码
复制代码

让nums:Vec<i32> = vec!1,2,3,4,5; let doubles: Vec<i32> = nums.into_iter().map(|n| n * 2).collect(); dbg!(nums); // 这个抛出 dbg!(双打);

此代码抛出,因为intointo_iter方法创建了一个"消耗迭代器";换句话说,从nums夺走所有权,并赋予它todoubles。因此,我们不能调用dbg!(nums)在doubles创建后。

如果我们想保持对nums访问权限,而是克隆其值,我们可以使用iter方法而不是into_iter。重要的是,Rust给了我们一个选择,转移所有权的能力可以帮助我们提高内存分配的效率。

We can also move simple values. In the code below, when our str variable is used as an argument for calculate_length , it is no longer accessible.

复制代码
复制代码

fn main() { let str = String::from("Hello world!"); let len = calculate_length(str); dbg!(str); // 这扔 } fn calculate_length(s: String) -> usize { s.len() }

在这里,我们可以通过使用ampersand&传递对我们字符串的引用来解决这个问题,而不是传递字符串本身。我们还需要更新函数参数才能获得引用:

复制代码
复制代码

fn main() { let str = String::from("hello"); let len = calculate_length(&str); dbg!(str,len); } fn calculate_length(s: &String) -> usize { s.len() }

要反其道而行之,并取消引用一个值,我们可以使用星号*。这些功能共同帮助我们安全高效地控制内存,正因为如此,Rust不需要依赖垃圾收集器,这使我们能够解锁更高的性能水平,而没有C等语言的风险,这使开发人员有更大的风险来了解他们在做什么!

总的来说,我学习和使用Rust的早期经验是非常积极的。入门感觉比我近年来尝试过的其他语言更困难,但我相信学习Rust已经让我更加了解我每天使用的高级语言的基本工作,我很高兴能在个人项目中更多地使用它。

如果您是Rust的新手或对学习这种语言感到好奇------特别是来自更高层次的语言------那么希望您觉得这篇文章有用。当然,这只是一个粗略的观点,有很多主题,如特征和寿命,超出了文章的范围。

相关推荐
传奇开心果编程1 小时前
【Xilem基础语法学与练】第8课:条件渲染(one_of)
学习·rust·前端框架
qwsaedca3 小时前
在Mac上跑 Kokoro TTS经验总结
rust·mac·tts
qwsaedca3 小时前
Kokoro TTS v1.1 voices 文件格式逆向分析
rust
老猿讲编程5 小时前
【Eclipse OpenSOVD学习之五】拓扑引擎(Topology)
学习·rust·eclipse·sovd
object not found5 小时前
Nuxt4去掉body中默认的边距
开发语言·后端·rust
梦醒沉醉1 天前
4、Rust参考手册——Crate和源文件
rust
chainbees1 天前
Windows 系统 Rust 运行环境搭建
rust
DreamLife☼1 天前
Agent开发环境搭建完全指南
python·docker·typescript·node·工业知识点
k4m7v2pz1 天前
从 Python 搬到 Rust:pyglet MIDI DAW 变成 egui 鬼畜采样器的迁移复盘
开发语言·python·rust
小灰灰搞电子1 天前
Rust+Slint 实现ModbusRTU从机调试助手源码分享
开发语言·rust·modbusrtu