Wie kann ich meine Rust-Funktion generischer und effizienter machen?

8

Ich habe eine Funktion, die funktioniert, aber spezialisierter ist, als ich es möchte, und es gibt einige Ineffizienzen, die ich gerne beheben würde.

Die funktionierende aber fehlerhafte Funktion:

%Vor%

Die Gründe, warum ich diese Implementierung nicht mag, sind:

  • i64 ist hart codiert und ich möchte diese Funktion für u64 und möglicherweise andere Rückgabetypen
  • wiederverwenden
  • es sammelt seine Eingabe, nur um sofort darüber zu iterieren, was ineffizient ist (Heap-Zuweisung ohne Grund)
  • Die an flat_map übergebene Sperrung kann in allen Fällen nicht von LLVM entfernt werden

und der nächste, den ich zu meiner idealen Funktion bekommen konnte:

%Vor%

Die Probleme, die ich sehe, sind:

  • Das an str::split_whitespace übergebene Argument ist ein String und wird nicht zu einem str gezwungen
  • Es ist nicht bekannt, dass das an str::split_whitespace übergebene Argument lange genug lebt
  • Result::unwrap beschwert sich nicht, dass das Merkmal core::fmt::Debug für den Typ <U as core::str::FromStr>::Err nicht implementiert ist.

Ich denke, dass mit cleveren Lifetime-Notation und Trait-Anforderungen mindestens zwei davon behoben werden könnten, und wer weiß, vielleicht gibt es einen Weg, drei für drei zu gehen.

Beispielcode mit einigen vorgeschlagenen Korrekturen:

%Vor%     
Camden Narzt 26.05.2016, 08:38
quelle

2 Antworten

8

Leider gibt es keine Möglichkeit, das zu tun, was Sie wollen, wenn Sie sowohl die Generizität als auch das Fehlen von Zuweisungen beibehalten. Der Grund dafür ist, dass Sie jemanden brauchen, der Ihre String-Daten besitzt, aber wenn flat_map(str::split_whitespace) über einen Iterator von eigenen Strings ausgeführt wird, dann gibt es niemanden mehr, der diese strings behält, weil str::split_whitespace nur die angefragte Zeichenfolge ausborgt . Wenn Sie jedoch die Eigentumsrechte in der Aufrufkette "pushen", können Sie nicht vollständig generisch sein und eigene Zeichenfolgen nach Wert akzeptieren.

Daher gibt es zwei Lösungen: den gesamten Iterator zu einem Vec<String> vorzusammeln (oder die Elemente, die von split_whitespace() zurückgegeben wurden, in eigene Strings umzuwandeln und sie wieder in Vec zu sammeln), oder ein Iterator von Referenzen.

Hier ist die allgemeinste Version, die ich mir für die erste Lösung vorstellen konnte:

%Vor%

(versuchen Sie es hier )

Es ist im Grunde das gleiche wie das erste, aber allgemeiner. Beachten Sie auch, dass Sie die Teile der Saite nach split_whitespace() nicht zuschneiden müssen - das letztere wird sicherstellen, dass die Teile der Saite keine Leerzeichen an ihren Seiten haben. Into<String> bound erlaubt es, sowohl &str als auch String iterators zu übergeben, und im letzteren Fall werden keine zusätzlichen Kopien erstellt.

Alternativ können Sie jede Zeile separat in eigene Strings aufteilen:

%Vor%

Hier müssen wir nur eine &str s von Iterator-Elementen erhalten, nicht String s, also habe ich AsRef<str> verwendet. Allerdings muss jede Zeile nicht nur in eine Sequenz von String s konvertiert werden; Diese Sequenz muss aus genau dem gleichen Grund, der oben beschrieben wurde, in einem Vektor gesammelt werden - sonst würde niemand die ursprünglichen Werte vom Typ S vor der Zerstörung behalten.

Aber es ist möglich, das .map(String::from).collect::<Vec<_>>() zu vermeiden, wenn Sie bereit sind, etwas Generizität zu verlieren. Dies ist die zweite Lösung, die ich oben erwähnt habe. Wir können einen Iterator über Referenzen akzeptieren:

%Vor%

(Probieren Sie hier )

Grob gesagt, S -Werte gehören nun jemand anderem und ihre Lebensdauer ist größer als der Bereich von iter_to_min() . Sie müssen also weder jedes Teil in String transformieren noch das gesamte Split-Ergebnis sammeln ein Code%. Sie können jedoch keine Vec<String> an diese Funktion übergeben. Sie können Vec<String> jedoch übergeben:

%Vor%

In all diesen Beispielen habe ich vec.iter() in Iterator geändert - das ist fast immer das, was Sie verwenden möchten, anstatt nur IntoIterator . So können Sie beispielsweise Sammlungen direkt an solche Funktionen übergeben. Zweitens habe ich Iterator condition hinzugefügt, was notwendig ist, damit U::Err: Debug funktioniert. Und schließlich, um das Problem mit "String not coercing to & amp; str" zu beheben, können Sie immer explizite Closures und Methodensyntax verwenden, die diesen Zwang für Sie tun würden.

    
Vladimir Matveev 26.05.2016, 10:21
quelle
3

Eine Lösung ohne zusätzliche Zuweisungen

%Vor%     
A.B. 26.05.2016 12:14
quelle

Tags und Links