在循环块外使用 enumerate 的索引

Using the index from enumerate outside the loop block

考虑这个求解 Advent of Code 2015 1.2 的例子。

fn main() {
    // advent of code 1.2 2015
    // you are at floor 0
    // if instruction is ) go one floor up, else go one floor down
    // what index has the character that makes you go below floor 0

    let instruction = ")))(((()))))";
    let mut floor = 0;

    for (i, c) in input.chars().enumerate() {
        if c.to_string() == ")" {
            floor += 1;
        } else {
            floor -= 1;
        }
        if floor < 0 {
            break;
        }
    }

    // will fail
    println!("floor: {}", i)
}

如何在循环块外访问i

读过 and this chapter of the book,我理解为什么我的代码失败了,但我不知道如何处理它并在外面使用i街区。

我的问题是我没有理解 Rust 中作用域的用途吗?如果我想在循环范围之外使用它,我是否应该将循环放在函数内部,return i

不能访问循环范围之外的循环变量。这不是 Rust 独有的 "problem";当今使用的大多数编程语言都有类似的范围规则,这些规则会导致相同的问题。


要解决你的 first version of the problem,你应该 "return" 索引,但你不需要一个函数。相反,您可以使用迭代器适配器:

fn main() {
    let maze = "***#***";

    let i = maze
        .chars()
        .enumerate()
        .find(|&(_, c)| c == '#')
        .map(|(i, _)| i);

    println!("# is at position: {:?}", i) // Some(3)
}

请注意,这 return 是一个 Option 来处理找不到字母的情况。


要解决您的 second version of the problem,您应该 "return" 索引,但您不需要函数。相反,您可以使用迭代器适配器:

fn main() {
    let instruction = ")))(((()))))";
    let mut floor = 0;

    let i = instruction
        .chars()
        .enumerate()
        .find(|&(_, c)| {
            if c == ')' {
                floor += 1;
            } else {
                floor -= 1;
            }

            floor < 0
        })
        .map(|(i, _)| i);

    println!("floor: {:?}", i) // Some(6)
}

请注意,这 return 是一个 Option 来处理找不到地板的情况。


当然,你可以选择早点用一个函数,return。做任何你能理解的事情。

您无需将代码放入函数中即可获得 i,您只需将其分配给一个新变量即可:

fn main() {
    let instruction = ")))(((()))))";
    let mut floor = 0;
    let mut breaking_index = None;

    for (i, c) in instruction.chars().enumerate() {
        if c.to_string() == ")" {
            floor += 1;
        } else {
            floor -= 1;
        }
        if floor < 0 {
            breaking_index = Some(i);
            break;
        }
    }

    // will not fail
    println!("floor: {:?}", breaking_index)
}