2017-07-18 3 views
1

Ich versuche, ein Übersetzer/Parser-Beispiel aus einem alten Compiler-Lehrbuch von C nach Rust zu portieren.Spähen bei stdin mit Übereinstimmung

Ich habe den folgenden Code:

use std::io::Read; 

fn lexan() { 
    let mut input = std::io::stdin().bytes().peekable(); 
    loop { 
     match input.peek() { 
      Some(&ch) => { 
       match ch { 
        _ => println!("{:?}", input.next()), 
       } 
      } 
      None => break, 
     } 
    } 
} 

An diesem Punkt bin ich nicht aktiv um die Eingabe zu analysieren versucht, meinen Kopf zu umgehen, wie match funktioniert. Ziel ist es, Parse-Zweige zum inneren Match hinzuzufügen. Leider versagt diese zu kompilieren, weil ich das Verständnis der Semantik von Spiel zu scheitern scheinen:

error[E0507]: cannot move out of borrowed content 
--> src/main.rs:7:18 
    | 
7 |    Some(&ch) => { 
    |     ^-- 
    |     || 
    |     |hint: to prevent move, use `ref ch` or `ref mut ch` 
    |     cannot move out of borrowed content 

Von dem, was ich verstehe, dieser Fehler ist, weil ich den Rückgabewert des match nicht besitzen. Die Sache ist, ich glaube nicht, dass ich den Rückgabewert beider Spiele verwende. Ich dachte vielleicht input.next() könnte das Problem gewesen sein, aber der gleiche Fehler tritt mit oder ohne diesen Teil (oder in der Tat, die gesamte println! Anruf).

Was fehlt mir hier? Es ist schon eine Weile her, dass ich Rust angeschaut habe (und nie in einem ernsthaften Maß an Anstrengung), und die meisten Suchergebnisse für Dinge dieser Art scheinen veraltet zu sein.

+0

Haben Sie versucht, was der Compiler vorgeschlagen? Was war daran nicht ausreichend? – Shepmaster

+0

Ich habe nicht, da ich nicht erwarte 'ch' sollte hier als veränderlich betrachtet werden. Durch die Änderung scheint sich das Problem jedoch im Code weiter zu verschieben. – user3662805

+0

Wenn ich Sie wäre, würde ich alle Eingaben in den Speicher lesen und dann über * das * iterieren. –

Antwort

1

Es hat nichts mit dem Rückgabewert von match oder sogar match selbst :: zu tun ist,

use std::io::Read; 

fn lexan() { 
    let mut input = std::io::stdin().bytes().peekable(); 
    if let Some(&ch) = input.peek() {} 
} 

Das Problem, dass Sie das Ergebnis der Peekable::peekzu binden versuchen, während es dereferencing (das ist, was die & in &ch tut). In diesem Fall ist der Rückgabetyp ein Option<&Result<u8, std::io::Error>>, da der Bytes Iterator Fehler aus dem zugrunde liegenden Stream zurückgibt. Da dieser Typ Copy nicht implementiert, erfordert der Versuch, den Typ zu dereferenzieren, dass Sie den Besitz des Werts übertragen. Sie können dies nicht tun, da Sie den ursprünglichen Wert nicht besitzen - also die Fehlermeldung.

Das Stück, das die Unfähigkeit zu kopieren verursacht, ist der Fehlertyp der Result. Aus diesem Grund können Sie eine Ebene tiefer anzeigen lassen:

match input.peek() { 
    Some(&Ok(ch)) => { 
     match ch { 
      _ => println!("{:?}", input.next()), 
     } 
    } 
    Some(&Err(_)) => panic!(), 
    None => break, 
} 

Beachten Sie, dass dieser Code ziemlich nahe ist allerdings zu sein uncompilable. Das Ergebnis von peek wird ungültig, wenn next aufgerufen wird, so viele kleine Änderungen an diesem Code wird die Borrow-Checker den Code fehlschlagen. Ich bin eigentlich ein wenig überrascht, dass das oben genannte auf Anhieb funktionierte.

Wenn Sie überhaupt nicht über Fehler egal war, konnte man

while let Some(&Ok(ch)) = input.peek() { 
    match ch { 
     _ => println!("{:?}", input.next()), 
    } 
} 

tun Leider kann man die Mitte gespalten, da dies die borrow von input verursachen würde während des Anrufs next dauern :

while let Some(x) = input.peek() { 
    match *x { 
     Ok(ch) => { 
      match ch { 
       _ => println!("{:?}", input.next()), 
      } 
     } 
     Err(_) => {} 
    } 

    // Could still use `x` here, compiler doesn't currently see that we don't 
} 
+0

Danke, ich verstand, was die & tat, aber es kam mir nicht in den Sinn, dass eine Bindung im Spiel stattfand (scheint jetzt offensichtlich).Zu Ihrer letzten Notiz: Warum würde es in diesem Fall eine Rolle spielen, wenn 'peek' während des Match-Blocks ungültig gemacht wird? Ich betrachte 'match' als (vage) semantisch einem Fall ähnlich, ohne durchzufallen. Sollte die Gültigkeit nicht irrelevant sein, nachdem 'input.next' aufgerufen wurde? – user3662805

+0

@ user3662805 Ich habe dem letzten Beispiel einen Kommentar hinzugefügt. TL; DR: das würde * nicht-lexikalische Lebenszeiten * erfordern, ein mit Spannung erwartetes Merkmal, aber keines, das wir jetzt haben. – Shepmaster