我来自C(在较小程度上,C ++)背景。我写了以下代码片段:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j| println!("= {}", j);
for k in my_array.iter() {
print_me(k);
}
}
编译并按预期运行,但后来我指定了传递给闭包print_me
的参数的类型:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j: i32| println!("= {}", j);
for k in my_array.iter() {
print_me(k);
}
}
我收到了编译错误:
error[E0308]: mismatched types
--> src/main.rs:6:22
|
6 | print_me(k);
| ^
| |
| expected i32, found &{integer}
| help: consider dereferencing the borrow: `*k`
|
= note: expected type `i32`
found type `&{integer}`
现在这让我很困惑,直到我在k
语句中将&k
更改为for
,这很好:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j: i32| println!("= {}", j);
for &k in my_array.iter() {
print_me(k);
}
}
似乎我误解了for
语法本身 - 或者可能是迭代器的确切工作方式 - 或者可能是指针的使用语法与指针相关[相关但不同于C ++]。
在构造for A in B { C1; C2; ... Cn }
中,A
和B
到底应该是什么?
答案 0 :(得分:10)
首先,这是the definition of for
in the reference的链接。
总而言之,B
是任何表达式,其值可以转换为实现Iterator<T>
特征的值,而A
是无可辩驳的模式绑定T
类型的值。
在您的具体情况下,slice::iter
会返回Iter<i32>
,implements Iterator<Item = &i32>
。也就是说,它不会产生i32
s,而是产生&i32
s。
因此,在第一个和第二个示例中,k
实际上绑定到&i32
s,而不是i32
s。当您指定闭包的类型时,实际上是指定错误的类型。最终示例的工作原因是因为A
是模式,不是变量名称。 <{1}} 实际所做的是“解构”&k
,将&i32
部分绑定到名为i32
的变量。
“无可辩驳”部分仅表示该模式必须始终工作。例如,k
for Some(x) in thingy
实施thingy
时无法执行Iterator<Option<_>>
; Some(x)
对于迭代器中的每个元素都不一定有效;因此,它是 refutable模式。
答案 1 :(得分:5)
许多迭代器实际上返回引用而不是值。当然,您必须检查.iter()
的返回类型,其格式应为Iterator<Item = X>
:X
将是返回变量的类型。
所以这里:
fn main() {
let my_array = [1, 2, 3];
let print_me = |j: i32| println!("= {}", j);
for k in my_array.iter() {
print_me(k);
}
}
此X
为&i32
(对i32
的引用),因此k
的类型为&i32
。
这就是为什么,在调用print_me
时,会出现错误:&i32
在预期i32
的位置传递。
这里有多种可能的修复方法:
为print_me
指定不同的类型:
let print_me = |j: &i32| println!("= {}", j);
取消引用k
:
print_me(*k);
在循环中通过解构更改k
的类型:
for &k in my_array.iter() { ... }
解构发生是因为for .. in
接受了一个无可辩驳的模式,因此您可以像在match
表达式中那样进行模式匹配,除了变量的类型具有以匹配(否则会出现编译器时间错误)。
为了更好地说明,我们可以使用稍微复杂的例子:
fn main() {
let my_array = [(1, 2), (2, 3), (3, 4)];
let print_me = |a: i32, b: i32| println!("= {} {}", a, b);
for &(j, k) in my_array.iter() {
print_me(j, k)
}
}
my_array
的类型为[(i32, i32)]
:一组2 i32
的元组。因此,.iter()
的结果是Iterator<Item = &(i32, i32)>
类型:对2 i32
元组&(i32, i32)
的元组引用的迭代器。
当我们使用无可辩驳的模式&(j, k)
时,我们会对元组进行解构以便:
j
(推断为i32
类型,仅适用,因为i32
为Copy
)k
((推断为类型i32
) j
和k
因此成为此元素中i32
的临时副本。