网站首页 > 开源技术 正文
Elimende Inagella在Unsplash上的照片
像许多开发人员一样,我通过专注于网络技术开始了我的编程生涯。我相信这是一个很好的起点,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 the panic! macro, but we can pass a custom error message which will help us quickly understand what went wrong:
let parsed_int_result = submitted_str.parse::<i32>();
let parsed_int = 匹配 parsed_int_result {
好的(数据)=>数据,
Err(错误)=>恐慌!(
给定的字符串不能解析为整数:{:?}",
错误
),
};
或者我们可以返回一个默认值——在这种情况下是0:
let parsed_int_result = submitted_str.parse::<i32>();
let parsed_int = 匹配 parsed_int_result {
好的(数据)=>数据,
Err(错误)=> 0,
};
还有一个简写方法:unwrap_or_default。
当然,这种行为在JavaScript中是可能的,但区别在于,在JavaScript中,您必须选择加入,而在Rust中,您必须使用unwrap来选择退出。
或者,换句话说,在JavaScript中,你必须有意识地处理错误。而在Rust中,你被迫要么处理错误,要么有意识地决定你只关心成功的道路。
可选值
Rust使用类似的方法来处理可选值。在TypeScript中,我们可以使用方便的?指示一个值可能undefined。
界面用户{
_id:字符串;
名称?:字符串;
}
函数 sayHello(用户:用户){
返回`Hello ${user.name}!`;
}
这个TypeScript代码将毫无问题地编译,即使我们有返回我们不想要的东西的风险!
但是,如果我们使用Option在Rust中编写类似的东西,我们会收到一个编译时错误。
结构用户{
_id:字符串,
名称:Option<String>,
}
fn say_hello(用户:用户)->字符串{
让名称 = 用户名;
格式!("你好{姓名}!”)
}
The code above warns us that we cannot use Option inside our format!macro — preventing us from returning something unexpected. Instead, we are forced to handle this possibility. Here’s one solution, using match :
结构用户{
_id:字符串,
名称:Option<String>,
}
fn say_hello(用户:用户)->字符串{
让名称:字符串 = 匹配用户名 {
一些(名称)=>名称,
None => "world".to_string(),
};
格式!("你好{姓名}!”)
}
再一次,这在TypeScript中是可以实现的——而且它更简洁。但两种语言之间的关键区别在于,在TypeScript中,开发人员有需要识别潜在的问题,因此我们最终不会返回"Hello undefined"但在Rust中,除非我们处理名称不可用的情况,否则我们的代码将无法编译。
在这样的简单例子中,很难认识到更冗长的方法的好处,因为很容易看出可能会出错什么。但是,如果您曾经开发过大型应用程序,很明显,Rust的选择退出方法可以使我们免于许多潜在的事故。
所有权和借贷
最后,我想谈谈所有权和借贷,这些概念在像Rust这样的低级语言中比像TypeScript这样的高级语言更有意义。
在TypeScript中,我们需要意识到我们是突变值还是克隆值。
const arrayToBeMutated: string[] = ["d", "c", "b", "a"];
const arrayToBeCloned: string[] = ["d", "c", "b", "a"];
arrayToBeMutated.sort();
arrayToBeCloned.toSorted();
console.log(arrayToBeMutated); // ["a", "b", "c", "d"]
console.log(arrayToBeCloned); // ["d", "c", "b", "a"]
在上面的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的新手或对学习这种语言感到好奇——特别是来自更高层次的语言——那么希望您觉得这篇文章有用。当然,这只是一个粗略的观点,有很多主题,如特征和寿命,超出了文章的范围。
猜你喜欢
- 2024-12-29 Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage4
- 2024-12-29 csdn免录可复制实现当前页面生成二维码链接
- 2024-12-29 8款必备的免费移动Web开发框架 移动webapp开发
- 2024-12-29 开发资源大整合:编程语言篇--JavaScript(1)
- 2024-12-29 栗子前端技术周刊第 30 期 - 2023 HTML 状态调查报告、React Conf 2024 等
- 2024-12-29 CSS 定位详解 css定位技术
- 2024-12-29 Spring boot + Jsoup 搭建,解析系统接口只需1分钟
- 2024-12-29 Scrapy-Redis分布式爬虫框架详解-邮乐网
- 2024-12-29 JavaScript引擎底层的工作原理 js底层运行机制
- 2024-12-29 自动化实践之:从UI到接口,Playwright给你全包了!
你 发表评论:
欢迎- 05-16东契奇:DFS训练时喷了我很多垃圾话 我不懂他为什么比赛不这么干
- 05-16这两球很伤!詹姆斯空篮拉杆不中 DFS接里夫斯传球空接也没放进
- 05-16湖人自媒体调查:89%球迷希望DFS回归79%希望詹姆斯回归
- 05-16Shams:湖人得到全能球员DFS 节省了1500万奢侈税&薪金空间更灵活
- 05-16G5湖人胜率更高!詹姆斯不满判罚,DFS谈5人打满下半场:这很艰难
- 05-16DFS:当东契奇进入状态 所有防守者在他面前都像个圆锥桶
- 05-16上一场9中6!DFS:不能让纳兹-里德这样的球员那么轻松地投三分
- 05-16WIDER FACE评测结果出炉:滴滴人脸检测DFS算法获世界第一
- 最近发表
-
- 东契奇:DFS训练时喷了我很多垃圾话 我不懂他为什么比赛不这么干
- 这两球很伤!詹姆斯空篮拉杆不中 DFS接里夫斯传球空接也没放进
- 湖人自媒体调查:89%球迷希望DFS回归79%希望詹姆斯回归
- Shams:湖人得到全能球员DFS 节省了1500万奢侈税&薪金空间更灵活
- G5湖人胜率更高!詹姆斯不满判罚,DFS谈5人打满下半场:这很艰难
- DFS:当东契奇进入状态 所有防守者在他面前都像个圆锥桶
- 上一场9中6!DFS:不能让纳兹-里德这样的球员那么轻松地投三分
- WIDER FACE评测结果出炉:滴滴人脸检测DFS算法获世界第一
- 湖人自媒体调查:89%球迷希望DFS回归 79%希望詹姆斯回归
- 一觉醒来湖人苦盼的纯3D终于到位 DFS能带给紫金军多少帮助
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)