Использование индекса из перечисления вне блока цикла
Рассмотрим пример решения 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
если я хочу использовать это вне области видимости цикла?
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)
}
Вы не можете получить доступ к переменной цикла за пределами области действия цикла. Это не "проблема", уникальная для 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
разобраться со случаем, когда пол не был найден.
Конечно, вы можете использовать функцию и вернуться рано. Делай то, что тебе понятно.