Eu tenho uma função que analisa uma string de entrada:
fn parse_input(s: &str) -> ((usize, usize), BTreeMap<(usize, usize), Tile>){
let mut start: (usize, usize) = (0,0);
let grid = s.split("\n").enumerate().flat_map(|(r,l)| {
l.chars().enumerate().map(move |(col, c)| {
let t = classify_tile(c);
match t {
Tile::Start => {
*start = (r, col);
((r,col), t)
},
_ => ((r,col), t)
}
})
}).collect::<BTreeMap<(usize, usize), Tile>>();
(start, grid)
}
Basicamente, quero capturar o valor r e col do bloco inicial (que é único, apenas uma ocorrência). Mas atualmente, se eu tentar modificar a tupla dentro do iterador, presumo que devido a motivos de empréstimo e escopo, o valor não será modificado fora do iterador. É importante que o iterador termine.
Uma solução alternativa seria procurar o bloco inicial no btreemap posteriormente, mas espero uma solução mais eficiente.
Devo apenas fazer isso como loops for aninhados? A iteração é realmente significativamente mais eficiente aqui?
editar: a função classify_tile retorna o tipo enum. Iniciar, Solo ou Tubo. A seção *start = (r,col) é a parte que não funciona. Essa foi minha tentativa de resolver isso. Todo o resto funciona.
Você pode fazer o que quiser, se reestruturar um pouco seu iterador.
Mas vamos primeiro abordar qual é o problema.
Como exemplo mais simples, vamos contar todas as letras maiúsculas (de uma forma boba):
Se tentarmos compilar isso, teremos o mesmo problema que você está tendo:
Por que é que?
O fechamento dado
map()
requer empréstimos mutáveiscount
, o que por si só é perfeitamente aceitável.O problema surge quando entramos
flat_map()
na mistura. Uma vez queflat_map()
produz potencialmente vários iteradores. Cada um desses iteradores produzidos requer empréstimos mutáveiscount
. É claro que isso não é permitido, uma vez que não podemos pedir emprestado nada mais de uma vez.No geral, isso é fácil de resolver, basta reestruturar o iterador:
ou
Resolver isso para o seu iterador poderia ser algo assim:
ou
Pode ser escrito de várias maneiras.