扩展库中的固有类型是不好的形式?

时间:2016-07-03 04:35:52

标签: types rust traits monkeypatching

我有一个函数downsample_vec,它接受​​Vec并根据其位置删除一些值。我无法对正确的特征进行注释(我只需要CloneIndex,但无法使其正常工作),所以我决定使用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)中查看。

1 个答案:

答案 0 :(得分: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是线性时间算法。这可能不是你想要的。