types - 为什么 Rust 编译器可以在单独的行上推断类型,但如果组合成一行则不能?
问题描述
为什么允许这样做:
let payload = "key1=value1";
let value: Vec<&str> = payload.split("=").collect();
let value = value[1];
println!("value is {:?}", value);
但不是这个:
let payload = "key1=value1";
let value: Vec<&str> = payload.split("=").collect()[1];
println!("value is {:?}", value);
这会导致错误:
error[E0282]: type annotations needed
--> src/main.rs:3:47
|
3 | let value: Vec<&str> = payload.split("=").collect()[1];
| ^^^^^^^
| |
| cannot infer type for type parameter `B` declared on the method `collect`
| help: consider specifying the type argument in the method call: `collect::<B>`
|
= note: type must be known at this point
两者不是等价的吗?它们是相同的要被解析的标记,编译器,只是分成不同的行。
我不明白第一个语法中存在哪些额外信息以使推理成为可能。
正如编译器警告的那样,也许这与不可能进行推理无关,但由于 Rust 语法、约定等原因,这是不允许的?
我试图理解为什么编译器无法推断它(即逻辑上缺少信息?只是由于约定?)而不是如何解决这个特定情况。
在编译器/解析器级别考虑这一点,
表达式:let value: Vec<&str> = payload.split("=").collect()
后缀:[1]
A(可接受):
(expression)
(expression')(suffix)
B(不可接受):
(expression)(suffix)
考虑到expression'
基本上添加value = value
,这是一个重言式并且不添加任何新信息,
如果expression
和expression'
具有相同程度的信息,为什么 B 对编译器无效?如果没有新信息,为什么它不能在 B 中推断出相同的东西?
我特别质疑“无法推断”部分,而不是“由于 Rust YY 语法/约定应该是 XX”)。
这只是编译器限制或强制易读性的故意错误,还是从一个案例添加到另一个案例的独特信息?(逻辑上不同的场景)。
解决方案
第一个片段,
let value: Vec<&str> = payload.split("=").collect();
let value = value[1];
是说将一个迭代器收集到一个向量(&str
s)中,然后将索引处的元素分配1
给value
(这将是 a &str
)。请注意,第一个value
被第二个所掩盖(它们具有不同的类型,因此如果您希望它们具有相同的名称,则需要执行此操作)。
部分由于类型注释,单行版本说的是不同的东西。
let value: Vec<&str> = payload.split("=").collect()[1];
这就是说将迭代器收集到 ...something... 并将其索引到1
并且结果类型应该是Vec<&str>
. 现在,由于在索引时可能会生成任意数量的类型Vec<&str>
(它可能是Vec<Vec<&str>>
,HashMap<usize, Vec<&str>>
甚至可能是此项目中定义的某些类型或依赖项),Rust 不会尝试在这里猜测。由于它不知道要收集到哪种类型,所以它放弃并返回该错误。
要正确执行此操作(在一行中),您可能希望使用 ol' turbofish 语法来指示您想要收集的类型。
let value = payload.split("=").collect::<Vec<_>>()[1];
请注意,元素的类型Vec
是已知的,因为它只是迭代器元素的类型。这就是为什么我们可以Vec<_>
用来让编译器推断出正确的类型。
还有一件事。为了更惯用,您可以char
在payload.split("=")
. payload.split'=')
也可以。
推荐阅读
- bash - 将明天的日期保存到变量中
- django - 表单不显示在模板中 - Django
- laravel - 使用 Laravel 在 VueJs 中显示动态图像
- flutter - 嵌套地图时如何将地图添加到飞镖列表中?
- c# - 您如何知道 url 是否指向 ASP.net 核心中的端点?
- python - 在 HTML 页面中呈现的 jinja 条件语句
- tizen - 如何在 tizen 中执行默认键操作?
- pytorch - 如何同时将多个张量移动到 Cuda 设备?
- laravel - 如何在 laravel 中为现有的 foreignId 列添加唯一约束?
- csv - 我应该在目录路径中创建 .parquet 文件以便以 parquet 格式写入数据框吗?