2016-07-03 8 views
1

У меня есть функция downsample_vec, которая принимает Vec и удаляет некоторые из ее значений в зависимости от их позиций. У меня была проблема аннотирования правильных черт (я только нужно Clone и Index, но не мог заставить его работать), поэтому я решил использовать self, чтобы увидеть, если я мог бы убедить компилятор, чтобы сделать правильные выводы:Это плохая форма для расширения встроенных типов в библиотеке?

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); 
      } 
     } 
    } 
} 

Это дает ошибку компиляции the value of the associated type `Output` (from the trait `std::ops::Index`) must be specified [E0191].

Я не совсем уверен, как указать тип вывода, и не нашел ссылок на то, как это сделать, просто блоги на чертах в целом. Мой главный ресурс: the rust vec .retain() source.

Это плохая форма для локального monkeypatch Vec как это в определенной библиотеке в первую очередь, или есть правильный способ сделать это? (Исходная отдельная функция, которую я написал, можно просмотреть в the playground).

ответ

4

В коде есть несколько вещей.

Во-первых, вы не можете написать impl -блочный тип, который вы не определяете в своем собственном ящике. Лучшее, что вы можете сделать, это определить новый признак и затем реализовать эту черту для иностранных типов. Это обычная практика и часто называется «чертой расширения», используя схему именования *Ext, например, MetadataExt. Таким образом, мы можем построить его так:

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

Теперь мы должны реализовать его для Vec. В вашем коде вы используете свойство IndexMut, как если бы вы хотели убедиться, что сам вектор изменчиво индексируется. Но так как Vec уже является конкретным типом (или, скорее, конструктором типа), компилятор уже знает, что он изменчиво индексируется. Так что это уже работает:

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

Если DownsampleExt черта находится в области видимости, вы можете вызвать downsample на любом Vec объекте.

Ваш код действия, однако, все еще содержит несколько ошибок/имеет несколько проблем:

  • Вы сказали «что берет VEC и возвращает копию с меньшими значениями», но код, который вы дали мы мутируем вектор вместо создания копии! Имейте в виду, что ваше описание не соответствует вашему коду.
  • Вам не проверить factor == 0
  • Ваш for цикл не работает: когда мы убираем элементы в то время как итерация по индексам, по Аннулируйте индексов. Всякий раз, когда вы удаляете один элемент, вы не должны увеличивать индекс в этой итерации.
  • Также обратите внимание, что ваш алгоритм работает в O (n²), потому что remove является алгоритмом линейного времени. Возможно, это не то, что вы хотите.
+0

Спасибо за указание проблемы с описанием функции. Я сделал слишком много изменений и ухищрений на вопрос, как я с ним справился. –