2014-11-16 17 views
5

Moim celem jest pobranie iteratora dla wszystkich elementów w macierzy obok numeru wiersza powiązanego z każdym elementem.Dożywotnie problem z odwzorowaniem iteratora na elementy macierzy

Poniżej znajduje się uproszczona wersja całego problemu, na który napotykam.

fn main() { 

    let mat = [ [1i32, 2, 3], 
       [4, 5, 6], 
       [7, 8, 9] ]; 

    // Create an iterator that produces each element alongside its row number. 
    let all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
     arr.iter().map(|elem| (row, elem)) // Error occurs here. 
    }); 

    for (row, elem) in all_elems { 
     println!("Row: {}, Elem: {}", row, elem); 
    } 

} 

Oto błąd Dostaję:

<anon>:10:9: 10:43 error: cannot infer an appropriate lifetime for lifetime parameter 'r in function call due to conflicting requirements 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
<anon>:10:24: 10:42 note: first, the lifetime cannot outlive the expression at 10:23... 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
           ^~~~~~~~~~~~~~~~~~ 
<anon>:10:24: 10:42 note: ...so type `|&i32| -> (uint, &i32)` of expression is valid during the expression 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
           ^~~~~~~~~~~~~~~~~~ 
<anon>:10:9: 10:43 note: but, the lifetime must be valid for the method call at 10:8... 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
<anon>:10:24: 10:42 note: ...so that argument is valid for the call 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
           ^~~~~~~~~~~~~~~~~~ 

Oto playpen link.

Problem wydaje się wynikać z niemożności wywnioskowania czasu życia w argumencie zamknięcia metody mapy, chociaż nie jestem pewien dlaczego.

  • Czy ktoś może wyjaśnić sprawę tutaj nieco jaśniej?
  • Czy jest możliwe utworzenie żądanego iteratora w inny sposób?

Odpowiedz

5

Nawet jeśli to nie jest bardzo jasne, kompilator nie może dowiedzieć się żywotność swojego wewnętrznego zamknięcia

|elem| (row, elem) 

Ponieważ zamknięcie przechwytuje row z jej otoczeniem (tutaj jest to ciało swojej zewnętrznej zamknięcie), dlatego nie powinno być w stanie przeżyć go.

Mimo to próbujesz zwrócić go owiniętego w obiekt Map<> zwrócony przez .map(..), a więc występują sprzeczne wymagania: twoje wewnętrzne zamknięcie jest proszone o przeżycie zakresu, na którym nie może przeżyć!

w prosty sposób uniknąć tego problemu jest, aby twoje wewnętrzne zamknięcie wziąć row jako argument, jak również i to zrobić, możemy skorzystać z:

  • repeat(..) która tworzy iterator powtarzając te same poz zawsze
  • .zip(..) metoda iteratorów, które pozwalają, aby przejść dwa iteratory jednocześnie

aby coś w ten sposób:

let mut all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
    arr.iter() 
     .zip(repeat(row)) 
     .map(|(elem, my_row)| (my_row, elem)) 
}); 

Ale w tym przypadku, możemy uczynić go jeszcze bardziej proste |(elem, my_row)| (my_row, elem) wygląda całkiem bezużyteczny:

let mut all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
    repeat(row).zip(arr.iter()) 
}); 
2

Innym sposobem na zwiększenie żywotności wewnętrznej zamknięcia |elem| (row, elem) byłoby oznaczyć go jako ruchome zamknięcie poprzez dodanie słowa kluczowego move. Spowoduje to również kompilację:

let all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
    arr.iter().map(move |elem| (row, elem)) 
}); 

To samo zachowanie można również zaobserwować, gdy próbuje się zwrócić (zapakowane) zamknięcie z funkcji.Poniższa funkcja nie skompilować, ponieważ żywotność zamknięcia jest związany przez całe życie lokalnej zmiennej row:

fn foo_fail() -> Box<Fn(u32) -> (u32, u32)> { 
    let row = 1; 
    Box::new(|elem| (row, elem)) 
} 

Korzystanie zamknięcie ruchomego zamiast zadziała prawidłowo:

fn foo_success() -> Box<Fn(u32) -> (u32, u32)> { 
    let row = 1; 
    Box::new(move |elem| (row, elem)) 
}