【问题标题】:Using the index from enumerate outside the loop block在循环块外使用枚举中的索引
【发布时间】:2023-03-16 23:15:02
【问题描述】:

考虑这个解决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

阅读了Understanding scope and shadowing matchesthis chapter of the book,我明白为什么我的代码失败了,但我不知道如何处理它并在块外使用i。 p>

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

【问题讨论】:

  • 卡尔,问一个单独的问题是可以的,但是把一个问题改写成另一个问题会很混乱。
  • @DietrichEpp 我明白这一点 - 但问题仍然是“使用循环块外枚举中的索引”。鉴于我得到的唯一答案,我理解我的示例让我看起来像是在寻找一种在字母表中查找 d 索引的方法,而这只是一个示例。
  • 好的,从上下文来看,我认为你是对的。我已恢复回滚。

标签: for-loop scope rust enumerate


【解决方案1】:

您无需将代码放入函数中即可获取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)
}

【讨论】:

    【解决方案2】:

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


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

    fn main() {
        let maze = "***#***";
    
        let i = maze
            .chars()
            .enumerate()
            .find(|&(_, c)| c == '#')
            .map(|(i, _)| i);
    
        println!("# is at position: {:?}", i) // Some(3)
    }
    

    请注意,这会返回一个Option 来处理未找到该字母的情况。


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

    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)
    }
    

    请注意,这会返回一个Option 来处理未找到楼层的情况。


    当然,您可以选择使用函数并提前返回。做你能理解的事。

    【讨论】:

    • 谢谢 - 但我意识到我应该更清楚地说明我需要遍历字符。我已经更新了问题中的代码示例。
    • @KarlAnka 编辑问题以使现有答案无效是高度不赞成的。您的编辑已经完成,因此我的回答完全是荒谬的,人们因为没有帮助而对其投反对票是合理的。
    • @DietrichEpp 我回答的第一句话是“你不能访问循环范围之外的循环变量。”。那 100% 回答了所提出的问题。任何超越,必然,必须是“更好的解决方案”,因为假设的解决方案是不可能的。
    • 虽然指导人们编写更惯用的 Rust 代码很有帮助,但有一个非常明显、简单且正确的替代方案,只需要更改三行代码。另一种选择是如此明显,完全怀疑它没有出现在这个答案中。当然,假定的解决方案是不可能的……这就是 OP 在这里提出问题的原因。我们可以将这个问题解释为“如何在块外使用 for 循环中的值?”或者,“请使用惯用的 Rust 重写我的代码。”
    • 最后,我觉得这个答案更能展示你编写惯用的 Rust 代码的技能,并且没有给 OP 任何他们缺乏的工具来解决未来类似的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 2017-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多