RustRover 中最常见的 Rust 编译器错误(上)| 技术解析

Rust 编译器相当挑剔, 如果它对输入的源代码不满意,可能会发出 400 多种不同的错误(而且每个月都在增加!)。有些错误极其罕见,另一些则每天都困绕着 Rust 开发者。在这个博文系列中,我们将介绍开发者在 RustRover(JetBrains 推出的专属 Rust IDE)中遇到的最常见 Rust 编译器错误消息,并说明如何避免这些错误。首先,我们来看一下“最常见错误”实际上指的是什么。

从 RustRover 的使用数据中识别最常见的错误

任何 RustRover 用户都可以选择向 JetBrains 发送其匿名使用数据。通过分析这些数据,我们可以观察各种用户模式并深入探究如何改进 IDE。当然,我们非常重视您的隐私,因此 IDE 收集的信息非常有限。例如,数据中的任何内容都无法追溯到用户。但匿名数据仍然可以告诉我们 IDE 的一般使用情况,例如最常生成的错误消息类型。

当选择加入的用户通过 IDE 启动 Cargo Build 命令(例如,通过触发需要构建项目的运行配置)并且 Rust 编译器发出错误时,我们就会记录错误代码。这不包括用户编写代码时出现的所有代码问题,仅包括在用户构建项目后仍然存在的问题。中间错误通常可以通过 IDE 的检查和快速修复处理。用户向我们发送的使用数据越多、使用 RustRover 的频率越高,我们就越能了解他们的体验,也就越能改进 IDE 的代码辅助功能。因此,感谢所有加入的用户通过其使用数据帮助我们改进 RustRover!

我们从运行 RustRover 的用户处收集错误代码,并根据遇到错误的用户数量对其排名。本系列的这一部分将讨论第 10 到 6 名最常见错误,下一部分将揭示前 5 名最常见错误。我们将研究这些错误背后的原因,探索简单示例,并探讨潜在修正方式。

常见错误 #10:E0412(使用的类型名称不在作用域内)

Rust 在类型声明点和类型名称用法之间保持严格区分。每个类型名称(包括泛型类型)都必须在某处声明,并且在其使用作用域内可用。如果编译器遇到类型名称用法但没有关于其声明点的任何信息,则会发出 E0412。大约 12% 的 RustRover 用户遇到过此错误。

假设您输入了 i42 而不是 i32, RustRover 会发现问题并高亮显示未知类型名称。编译器提供了更多详细信息并建议修正,点击编译器输出中的 Apply fix(应用修正)按钮即可轻松应用:

其他导致 E0412 的情况包括:

  • 忘记声明类型。

  • 将类型导入到当前作用域。

  • 引入泛型类型名称而使编译器无法访问类型。

要修正这一问题,可以提供类型声明(声明结构或正确引入泛型类型名称)或将类型引入作用域(通过 use 子句)。官方 E0412 错误说明给出了此错误的更多示例。

常见错误 #9:E0061(调用函数时传递的实参数量无效

虽然 RustRover 可以感知到这个错误并提供一系列修正,但 13% 的 RustRover 用户会在构建项目之前忽略这个错误。

错误本身不需要过多解释:我们有一个函数,要么在当前作用域中声明,要么从其他地方导入,而调用点给出的实参太少或太多。我们来看一个示例,并比较 RustRover 的建议和 Rust 编译器的建议:

这个示例展示了一个常见场景:打开文件。如果我们习惯了使用其他编程语言编码,就可能提供第二个实参,忘记在 Rust 中这个方法只需要一个实参。RustRover 和 Rust 编译器都建议移除第二个实参。很好,我们不需要构建项目就可以从 IDE 获得实用建议。注意代码中的红色波浪线,它们通常都有意义!

如果调用的函数是在我们自己的代码中定义的,情况就更有趣了。假设我们继续添加到相同的代码示例:

在这种情况下,RustRover 建议向函数添加形参作为第一个替代方案,这应该没有问题。但 Rust 编译器则坚持将其移除。这种差异有其原因。编译器的工作是确保程序正确,为此,最简单的方式就是消除调用点的额外实参。然而,IDE 的作用是让您更接近您想要达成的目标。如果您是为自己的函数输入了这个实参,那么您很有可能是有意为之,因此 RustRover 会尝试帮助您完成工作。

常见错误 #8:E0282(编译器无法推断类型并要求类型注解

有时编译器会不知所措,无法确定变量所需的类型,只能建议手动添加类型注解。如果您遇到过这个错误,您并不孤单,13.5% 的 RustRover 用户也遇到过。

E0282 这样的错误主要源于泛型性。许多库函数都采用泛型类型形参,但编译器必须将这些形参实例化为具体类型,因而陷入困惑。请查看以下示例:

我们想要将字符串中的数字收集到容器中。然而,编译器不能确定它们是什么类型的数字或什么类型的容器。

编译器建议首先指定容器类型。但是,如果应用此修正,我们将再次遇到相同类型的错误,涉及 str::parsecollectparse 都是泛型方法,但编译器需要知道确切类型才能编译使用它们的代码。请注意,RustRover 没有高亮显示错误,因为我们仍在完善其类型检查功能。

可以通过多种方式修正这个问题,因为不止一个地方可以添加类型注解。我们可以指定 numbers 向量的具体类型:

let numbers: Vec = "1  5     6   3"

或者我们可以在调用 collect 时提及相同的类型:

   .collect::<Vec>();

最后,我们可以在不同的地方提及不同的类型:

let numbers = "1  5     6   3"
   .split_whitespace()
   .map(str::parse::)
   .map(Result::unwrap)
   .collect::<Vec>();

这个错误很容易修正,指定需要的类型即可。

常见错误 #7:E0432(import 未解析

RustRover 提供了大量自动补全功能。例如,我们首先在代码中引入正则表达式:

如果选择第一个建议,除了补全本身,还会发生两件事:

  • regex crate 的依赖将添加到您的Cargo.toml中。

  • use regex::Regex; 子句将添加到文件顶部。

添加这样的 use 子句时,import 会自动正确写入。但有时您需要手动编写 import,这时就可能出现 E0432 错误。15.5% 的 RustRover 用户会不时遇到这种情况,最有可能是因为他们拼错了 crate 或模块名称,尝试导入不存在的内容,或者从某处复制粘贴后将错误的 use 子句带入代码。第一个建议始终是检查依赖项和名称。

有时 RustRover 可以帮助防止此错误。如果知道我们尝试导入的 crate,它可以在您从外部源粘贴代码时建议添加依赖项,或者通过以下快速修复提供支持:

将相应依赖项添加到Cargo.toml可以立即修正此错误。在 crate 可用后,对 use 子句中的其他路径组件使用自动补全能够避免出现更多名称问题。另请注意,某些名称的可用性可能取决于 crate 的启用功能。

supercrate 这样的特殊路径名称也可能存在问题,特别是在不同的 Rust 版本中要以不同的方式处理。请参阅官方说明了解详情。

常见错误 #6:E0382(内容移动到其他位置后变量才被使用

接下来是所有权问题, 17% 的 RustRover 用户遇到过这个错误。官方说明相当详细,并提供了许多示例。可惜,RustRover 在这里没有太大帮助。如果禁用外部 linter,RustRover 的内部机制不会发现以下代码有任何问题:

fn main({
   let vec = vec![12345];
   let mut sum = 0;
   for v in vec {
       sum += v;
   }
   println!("Sum of {vec:?} elements is {sum}");
}

这段看似无辜的代码在其他几种编程语言中完全合法。我们有一个向量,想要计算其元素的总和。例如,假设我们使用 C 语言,不知道迭代器的函数式编程技巧,我们需要编写传统的 for 循环。完成所有求和后,我们就可以输出向量和计算结果。右侧?

在 Rust 中不行,因为它有所有权规则。

问题在于,for 循环中的数据源扩展到具有整个向量的所有权的 into_iter() 调用。因此,尝试访问 println! 中向量的元素时,编译器会表示它已被移动。

修正很简单,并且由编译器建议:迭代 &vec,避免将其移入循环,而应改为借用

一般来说,建议始终跟踪值所有权。移动值和借用值是 Rust 的基本概念, 理解它们是每个学习者的首要任务。

更新一览

在博文系列的第一部分中,我们根据 RustRover 中的使用数据定义了最常见的 Rust 编译器错误,并讨论了第 10 到第 6 名的错误。在下一部分中,我们将探索最常见的 5 个错误,并尝试回答每个 Rust 开发者都会考虑的问题:“Rust 的哪一部分最麻烦?”


本博文英文原作者:Vitaly Bragilevsky


RustRover 相关阅读

关于 RustRover

RustRover 是 JetBrains 在 2023 年推出的面向 Rust 开发者的全新 IDE,正处于公开预览阶段,供大众免费使用体验。

进一步了解 RustRover

⏬ 戳「阅读原文」了解更多信息

本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

TIOBE 2023 年度编程语言:C# 某中学采购“智能互动宣泄仪”——实则为任天堂 Wii 的套壳 Linux 的 Rust 试验取得成功、Firefox 能否抓住机会……关于开源的 10 条预测 女高管开除员工事件后续:公司董事长称员工“惯犯”并质疑“学历简历造假” 开源神器 LSPosed 宣布停更,作者称遭受大量恶意攻击 被女高管违法开除员工发声,因反对用盗版 EDA 工具设计芯片遭针对 2024 前端圈“开年之战”:React 挖坑不填,要靠文档来补? Linux Kernel 6.7 正式发布 中文 JDK 教程网站正式上线,助力开发者掌握 Java 编程语言 罗永浩称“荣耀任意门”抄袭锤子开源软件 One Step
{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/5494143/blog/10773826