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::parse
。collect
和 parse
都是泛型方法,但编译器需要知道确切类型才能编译使用它们的代码。请注意,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 的启用功能。
super
或 crate
这样的特殊路径名称也可能存在问题,特别是在不同的 Rust 版本中要以不同的方式处理。请参阅官方说明了解详情。
常见错误 #6:E0382(内容移动到其他位置后变量才被使用)
接下来是所有权问题, 17% 的 RustRover 用户遇到过这个错误。官方说明相当详细,并提供了许多示例。可惜,RustRover 在这里没有太大帮助。如果禁用外部 linter,RustRover 的内部机制不会发现以下代码有任何问题:
fn main() {
let vec = vec![1, 2, 3, 4, 5];
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 相关阅读
⏬ 戳「阅读原文」了解更多信息
本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Bytebase 2.13.1 - 支持 Apache Doris
🚀 新功能 支持 Apache Doris。 支持在对 MySQL 执行 DML 之前备份数据。 支持实例的最大连接数,用以控制每个实例的并发任务数量。 支持对导出数据的压缩和加密。 🔔 重大变更 Bytebase API 的更改:重命名了预定义角色。如果您在使用这些角色,请更新您的代码: 工作区级别:OWNER 更改为 workspaceAdmin,DBA 更改为 workspaceDBA,DEVELOPER 更改为 workspaceMember。 项目级别:OWNER 更改为 projectOwner,DEVELOPER 更改为 projectDeveloper,QUERIER 更改为 projectQuerier,EXPORTER 更改为 projectExporter,VIEWER 更改为 projectViewer,RELEASER 更改为 projectReleaser。 🎄改进 支持在 Schema 编辑器中编辑索引。 在 SQL 编辑器中,按项目和数据库分组工作表。 支持在环境发布策略中选择自定义项目角色。 🎠 社区 视频:为什么商业基础软件要开源? 📕 安...
- 下一篇
新一代通信协议 - Socket.D
一、简介 Socket.D 是一种二进制字节流传输协议,位于 OSI 模型中的5~6层,底层可以依赖 TCP、UDP、KCP、WebSocket 等传输层协议。由 Noear 开发。支持异步流处理。其开发背后的动机是用开销更少的协议取代超文本传输协议(HTTP),HTTP 协议对于许多任务(如微服务通信)来说效率低下。 二、设计目标 协议接口丰富,包括 Send, SendAsRequest, SendAndSubscribe,Reply,ReplyEnd 支持应用层流量控制 支持单连接双向、多次复用 支持断连后自动重连 可以更好的使用 WebSocket 协议 三、消息驱动 网络通信是异步的,Socket.D 协议包含这一点,并将所有通信建模为在单个网络连接(TCP)上的、多路复用的消息流,在等待响应时从不同步阻塞。 响应式宣言指出: 反应式系统依赖异步的消息传递,从而确保了松耦合、隔离、位置透明的组件之间有着明确边界。 这一边界还提供了将失败作为消息委托出去的手段。 使用显式的消息传递,可以通过在系统中塑造并监视消息流队列, 并在必要时应用回压, 从而实现负载管理、 弹性以及流...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8