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

Is it bad form to extend inherent types in a library?

我有一个函数 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可以查看)

您的代码有一些问题。

首先,您不能为您未在自己的包中定义的类型编写 impl 块。您能做的最好的事情就是定义一个新特征,然后为外部类型实现该特征。这是一种常见的做法,通常称为 "extension trait",使用命名方案 *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 特征在范围内,您可以在任何 Vec 对象上调用 downsample

但是,您的操作代码仍然存在一些bugs/has几个问题:

  • 你说 "that takes a Vec and returns a copy of it with fewer values",但你给我们的代码改变了矢量而不是创建副本!请注意,您的描述与您的代码不符。
  • 您没有检查 factor == 0
  • 您的 for 循环不起作用:当我们在遍历索引时删除元素时,会使索引无效。每当您删除一个元素时,您都不能在该迭代中增加索引。
  • 另请注意,您的算法在 O(n²) 内运行,因为 remove 是线性时间算法。这可能不是你想要的。