2014-10-13 10 views
6

Interesuje mnie podglądanie w strumieniu postaci. Według mojej wiedzy, Peekable byłaby drogą do zrobienia. Nie mogę całkiem wymyślić, jak z niego korzystać.Jak korzystać z Peekable Rusta?

Pierwsza próba:

fn trawl<I, E>(pk: &mut I) where I: std::iter::Peekable<Result<char, E>> { 
    loop { 
     let cur = pk.next(); 
     let nxt = pk.peek(); 
     match (cur, nxt) { 
      (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()), 
      _ =>(), 
     } 
    } 
} 

fn main() { 
    trawl(&mut std::io::stdio::stdin().chars()); 
} 

To nie skompilować z

> rustc /tmp/main.rs 
/tmp/main.rs:1:37: 1:73 error: `std::iter::Peekable` is not a trait 
/tmp/main.rs:1 fn trawl<I, E>(pk: &mut I) where I: std::iter::Peekable<Result<char, E>> { 
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
error: aborting due to previous error 

Dobra, dość fair. Nie w pełni zrozumieć cechy jeszcze więc staram się przekazać iterator i następnie utworzyć peekable wersję:

fn trawl<I, E>(it: &mut I) where I: Iterator<Result<char, E>> { 
    let mut pk = it.peekable(); 
    loop { 
     let cur = pk.next(); 
     let nxt = pk.peek(); 
     match (cur, nxt) { 
      (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()), 
      _ =>(), 
     } 
    } 
} 

fn main() { 
    trawl(&mut std::io::stdio::stdin().chars().peekable()); 
} 

zawiedzie to z

> rustc /tmp/main.rs 
/tmp/main.rs:2:18: 2:20 error: cannot move out of dereference of `&mut`-pointer 
/tmp/main.rs:2  let mut pk = it.peekable(); 
           ^~ 
/tmp/main.rs:7:65: 7:70 error: cannot move out of dereference of `&`-pointer 
/tmp/main.rs:7    (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()), 
                       ^~~~~ 
note: in expansion of format_args! 
<std macros>:2:23: 2:77 note: expansion site 
<std macros>:1:1: 3:2 note: in expansion of println! 
/tmp/main.rs:7:39: 7:77 note: expansion site 
error: aborting due to 2 previous errors 

Może ktoś wyjaśnić:

  • dlaczego Peekable nie może pojawić się w typie funkcji z powodu braku bycia cechą,
  • co oznacza kompilator, gdy mówi "wyprowadzić się z dereferencji" i
  • Jak mogę rozwiązać jedno lub oba?

Trzecia wersja

fn trawl<I, E>(mut it: I) where I: Iterator<Result<char, E>> { 
    let mut pk = it.peekable(); 
    loop { 
     let cur = pk.next(); 
     let nxt = pk.peek(); 
     match (cur, nxt) { 
      (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()), 
      // (Some(i),) => println!("{}", i.ok()), 
      _ =>(), 
     } 
    } 
} 

fn main() { 
    trawl(std::io::stdio::stdin().chars().peekable()); 
} 

ten nie powiedzie się z:

> rustc /tmp/main.rs 
/tmp/main.rs:7:65: 7:70 error: cannot move out of dereference of `&`-pointer 
/tmp/main.rs:7    (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()), 
                       ^~~~~ 
note: in expansion of format_args! 
<std macros>:2:23: 2:77 note: expansion site 
<std macros>:1:1: 3:2 note: in expansion of println! 
/tmp/main.rs:7:39: 7:77 note: expansion site 
error: aborting due to previous error 

ja nie rozumiem, co rdza mówi do mnie tutaj, jak Iterator.next miałoby inny typ zwrotu z Peekable.peek.

Odpowiedz

5

Peekable nie jest cechą, a zatem nie może być stosowany jako granica, która sugeruje, że może to oznaczać jeden z wielu typów. Jest to pojedynczy, konkretny, konkretny typ, struct Peekable<A, T>.Jak zaobserwowałeś, jest on konstruowany przez wywołanie metody peekable() na iteratorze, co zmienia ją w coś, co jest peekable.

Oto jak chcesz go używać, jeśli tylko chciał wziąć iterator:

fn trawl<I, E>(iter: I) where I: Iterator<Result<char, E>> { 
    let pk = pk.peekable(); 
    … 
} 

Należy również zauważyć, że metoda peekable() trwa przez siebie wartości; nie można tam wstawić odwołania do iteratora.

Alternatywą, która jest czego dąży do lecz byłbym generalnie mniej skłonny ku, byłoby wymagać argument za peekable, kładąc ciężar na rozmówcy, jak miałeś:

fn trawl<I, E>(pk: Peekable<E, I>) where I: Iterator<Result<char, E>> { 
    … 
} 
+0

Nie wiedziałem tego o stdin. Dziękuję Ci. – troutwine

+2

Uwaga dla przyszłych czytelników: kiedy ta odpowiedź została napisana, ['stdin()' było trudne do bezpiecznego użytkowania] (https://github.com/rust-lang/rust/issues/14434). Nie ma to już miejsca, ponieważ problem został rozwiązany w grudniu 2014 r. – kiwidrew

4

Peekable jest rzeczywiście struct, a nie cecha. Jeśli chcesz wziąć Peekable, można zdefiniować swoją funkcję tak:

fn trawl<E, I>(it: Peekable<I>) where I: Iterator<Result<char, E>> { 
    ... 
} 

Twoja druga realizacja zawodzi skompilować ponieważ peek trwa self ujęciu wartościowym (czyli zużywa iteracyjnej, wracając nowy) , więc nie można go nazwać odwołaniem &mut. Większość kodu po prostu trwa iteracyjnej przez wartość zamiast przez odniesienie:

fn trawl<E, I>(it: I) where I: Iterator<Result<char, E>> { 
    let it = it.peekable(); 
    ... 
} 

Jeśli nie chcesz, aby przesunąć iterator do funkcji takich jak trawl, można użyć metody by_ref() aby utworzyć nowy iterator, która posiada na &mut referencyjny:

let mut my_iterator = /* whatever */; 
trawl(my_iterator.by_ref()); 
// my_iterator is still usable here 

Jeśli chodzi o styl idzie, chciałbym powiedzieć, że druga forma jest lepsza droga, jako pierwszych przecieków, co w zasadzie szczegółów wdrażania.

+0

Jeśli iterator jest przekazywany przez wartość do "trałowania", to w jaki sposób przejdziemy przez jego zawartość, co zmutuje Iterator? Jestem zdezorientowany tym, co należy tutaj zrobić, aby osiągnąć - w duchu - to, co zamierzałem osiągnąć przy drugim wdrożeniu. – troutwine

+0

Jeśli iterator jest przekazywany przez wartość do 'trasera ', funkcja jest jego właścicielem i może robić z nim, co chce. Możesz zrobić 'fn trawl (it: I) {let mut it = it; ...} ', aby umożliwić iterację po iteratorze. Istnieje również skrót do tego, który jest dokładnie taki sam w semantykach: 'fn trawl (mut it: I) {...}'. – sfackler