Использование индекса из перечисления вне блока цикла

Рассмотрим этот пример решения 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 вне блока цикла?

Прочитав Понимание области действия и совпадений с теневым копированием и эта глава книги, я понимаю, почему мой код не работает, но я не могу понять, как с этим справиться и использовать i вне блока.

Моя проблема в том, что я не понял назначение областей в Rust? Должен ли я поместить цикл внутри функции и вернуть i, если я хочу использовать его вне области действия цикла?


person Karl Anka    schedule 20.03.2018    source источник
comment
Карл, можно задать отдельный вопрос, но переформулировать один вопрос в другой вопрос — это сбивает с толку.   -  person Dietrich Epp    schedule 20.03.2018
comment
@DietrichEpp Я понимаю это, но вопрос остается прежним. Использование индекса из перечисления вне блока цикла. И, учитывая единственный ответ, который я получил, я понял, что мой пример выглядел так, будто я просил способ найти индекс d в алфавите, тогда как это был просто пример.   -  person Karl Anka    schedule 20.03.2018
comment
Ладно, судя по контексту, я думаю, ты прав насчет этого. Я восстановил откат.   -  person Dietrich Epp    schedule 20.03.2018


Ответы (2)


Вам не нужно помещать код в функцию, чтобы получить 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)
}
person Paulo Almeida    schedule 20.03.2018

Вы не можете получить доступ к переменной цикла вне области действия цикла. Это не уникальная «проблема» Rust; большинство языков программирования, используемых сегодня, имеют схожие правила области видимости, которые приводят к той же проблеме.


Чтобы решить вашу первую версию проблемы, вы должны "вернуть" индекс, но вам не нужна функция для тот. Вместо этого вы можете использовать адаптеры итераторов:

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

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

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

Обратите внимание, что это возвращает Option для обработки случая, когда буква не найдена.


Чтобы решить вашу вторую версию проблемы, вы должны "вернуть" индекс, но вам не нужна функция для тот. Вместо этого вы можете использовать адаптеры итераторов:

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 для обработки случая, когда этаж не найден.


Конечно, вы можете использовать функцию и вернуться раньше. Делайте все, что вам понятно.

person Shepmaster    schedule 20.03.2018
comment
Спасибо, но я понимаю, что должен был более четко указать, что мне нужно перебирать символы. Я обновил пример кода в вопросе. - person Karl Anka; 20.03.2018
comment
@KarlAnka, редактирующий вопрос, чтобы сделать существующие ответы недействительными, крайне не одобряется. Ваши правки сделали мой ответ совершенно бессмысленным, и было бы разумно, чтобы люди понизили его голос за то, что он бесполезен. - person Shepmaster; 20.03.2018
comment
Шепмастер... Я не думаю, что этот ответ на самом деле касается вопроса, поскольку он был изначально написан до редактирования. Карл спрашивает, как получить доступ к переменной цикла вне цикла, а не просит вас дать лучшее решение для фрагмента кода, который используется в качестве примера. - person Dietrich Epp; 20.03.2018
comment
Я сожалею об этом. Однако я не думаю, что это отвечает на мой вопрос, почему я обновил пример до того, где необходим цикл. Нахождение индекса d в этом сломанном алфавите было просто простым примером. - person Karl Anka; 20.03.2018
comment
@DietrichEpp Самое первое предложение моего ответа: Вы не можете получить доступ к переменной цикла за пределами области действия цикла. Это на 100% отвечает на заданный вопрос. Все, что выходит за его пределы, по необходимости должно быть лучшим решением, поскольку положенное решение невозможно. - person Shepmaster; 20.03.2018
comment
@DietrichEpp Считаете ли вы, что обновленная версия ответа теперь значительно лучше, поскольку она применила ту же логику во второй раз? - person Shepmaster; 20.03.2018
comment
Хотя полезно направлять людей для создания более идиоматичного кода на Rust, существует очень очевидная, простая и правильная альтернатива, которая требует изменения всего трех строк кода. Альтернатива настолько очевидна, что совершенно подозрительно, что она отсутствует в этом ответе. Конечно, предложенное решение невозможно ... поэтому ОП задал вопрос здесь. Мы можем интерпретировать вопрос так: как я могу использовать значение из цикла for вне блока? или, Пожалуйста, перепишите мой код, используя идиоматический Rust. - person Dietrich Epp; 20.03.2018
comment
В конце концов, я чувствую, что этот ответ служит больше для демонстрации ваших навыков написания идиоматического кода Rust и не дает OP никаких инструментов, которых им не хватает для решения подобных проблем в будущем. - person Dietrich Epp; 20.03.2018