2016-07-03 31 views
1

Ich habe eine Funktion downsample_vec, die eine Vec nimmt und einige ihrer Werte aufgrund ihrer Positionen entfernt. Ich hatte die richtigen Züge Probleme mit Anmerkungen versehen (ich brauchte nur Clone und Index, kann es aber nicht funktioniert), so habe ich beschlossen, self zu verwenden, um zu sehen, ob ich die Compiler davon überzeugen kann, die richtigen Schlüsse zu machen:Ist es eine schlechte Form, inhärente Typen in einer Bibliothek zu erweitern?

impl Vec<IndexMut<usize>> { 
    fn downsample<usize>(&mut self, factor: usize) { 
     let len = self.len(); 
     if factor > len { 
      self.clear(); // downsample factor skips all elements 
     } else if factor == 1 { 
      return; // no actual downsampling 
     } 

     for ind in 0..len() { 
      if ind % factor != 0 { 
       self.remove(ind); 
      } 
     } 
    } 
} 

Dies ergibt den Kompilierungsfehler the value of the associated type `Output` (from the trait `std::ops::Index`) must be specified [E0191].

Ich bin nicht genau sicher, wie man den Ausgabetyp angibt, und fand keine Hinweise, wie dies zu tun ist, nur Blogs auf Eigenschaften im Allgemeinen. Meine Hauptressource war the rust vec .retain() source.

Ist es schlechte Form zu lokal Monkeypatch Vec wie folgt in einer bestimmten Bibliothek an erster Stelle, oder gibt es einen richtigen Weg, dies zu tun? (Die ursprüngliche separate Funktion, die ich geschrieben habe, ist in the playground sichtbar).

Antwort

4

Es gibt ein paar Dinge über Ihren Code.

Zuerst können Sie keinen impl-Block für einen Typ schreiben, den Sie nicht in Ihrer eigenen Kiste definieren. Das Beste, was Sie tun können, ist, ein neues Merkmal zu definieren und dieses Merkmal dann für fremde Typen zu implementieren. Dies ist etwas, was allgemein üblich ist und oft "Erweiterungsmerkmal" genannt wird, wobei das Benennungsschema *Ext verwendet wird, wie zum Beispiel MetadataExt. So können wir es wie so bauen:

trait DownsampleExt { 
    fn downsample(&mut self, factor: usize); 
} 

Jetzt haben wir es implementieren für Vec. In Ihrem Code verwenden Sie das Merkmal IndexMut, als ob Sie sicherstellen möchten, dass der Vektor selbst veränderbar ist. Aber da bereits ein konkreter Typ (oder besser Typkonstruktor) ist, weiß der Compiler bereits, dass er veränderbar indexierbar ist. Also das bereits funktioniert:

impl<T> DownsampleExt for Vec<T> { 
    fn downsample(&mut self, factor: usize) { 
     // action code 
    } 
} 

Wenn das DownsampleExt Merkmal im Gültigkeitsbereich befindet, können Sie downsample auf jedem Vec Objekt aufrufen.

Ihr Aktionscode jedoch noch ein paar Bugs enthält/hat ein paar Probleme:

  • Du hast gesagt, „die eine Vec nimmt und eine Kopie davon mit weniger Werte“, aber der Code, den Sie gab Wir mutieren den Vektor anstatt eine Kopie zu erstellen! Beachten Sie, dass Ihre Beschreibung nicht mit Ihrem Code übereinstimmt.
  • Sie prüfen nicht für factor == 0
  • Ihre for Schleife funktioniert nicht: wenn wir Elemente entfernen, während über die Indizes Iterieren, die invalidate die Indizes. Wenn Sie ein Element entfernen, dürfen Sie den Index in dieser Iteration nicht erhöhen.
  • Beachten Sie auch, dass Ihr Algorithmus in O (n²) läuft, weil remove ein linearer Zeitalgorithmus ist. Dies ist möglicherweise nicht das, was Sie wollen.
+0

Vielen Dank für das Problem der Funktionsbeschreibung. Ich hatte zu viele Änderungen an der Frage vorgenommen, als ich damit herumhantierte. –