Rust中for循环的确切定义是什么?

时间:2014-12-01 09:07:40

标签: for-loop reference iterator rust

我来自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 }中,AB到底应该是什么?

2 个答案:

答案 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的位置传递。


这里有多种可能的修复方法:

  1. print_me指定不同的类型:

    let print_me = |j: &i32| println!("= {}", j);
    
  2. 取消引用k

    的值
    print_me(*k);
    
  3. 在循环中通过解构更改k的类型:

    for &k in my_array.iter() { ... }
    
  4. 解构发生是因为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类型,仅适用,因为i32Copy
    • 第二个元素绑定到k((推断为类型i32

    jk因此成为此元素中i32的临时副本。