通过32位整数索引向量

时间:2016-11-24 09:26:49

标签: rust

在Rust中,使用usize对向量进行索引,因此在编写

let my_vec: Vec<String> = vec!["Hello", "world"];
let index: u32 = 0;
println!("{}", my_vec[index]);

您收到错误,因为索引应该是usize类型。我知道可以通过将索引显式转换为usize

来解决这个问题
my_vec[index as usize]

但这写起来很乏味。理想情况下,我只是通过实现

来重载[]运算符
impl<T> std::ops::Index<u32> for Vec<T> { ... }

但这是不可能的,因为Rust禁止这个(因为特征和结构都不是本地的)。我能看到的唯一选择是为Vec创建一个包装类,但这也意味着必须编写许多函数包装器。有没有更优雅的方法来解决这个问题?

2 个答案:

答案 0 :(得分:6)

如果没有明确的用例,很难推荐最佳方法。

这里基本上有两个问题:

  • 你真的需要索引吗?
  • 你真的需要使用u32作为索引吗?

使用函数式编程样式时,通常不需要索引,因为您操作迭代器。在这种情况下,Vec仅为Index实现usize这一事实并不重要。

如果您的算法确实需要建立索引,那么为什么不使用usize?有很多方法可以从u32转换为usize,在最后一刻转换可能是一种可能性,但是还有其他网站可以进行转换,如果找到阻塞点(或创建)只有少数几次转换,你才能逃脱。

至少,这是YAGNI的观点。

个人而言,作为一个类型怪物,我倾向于包装很多东西。我只是想添加语义信息,因为让我们面对它Vec<i32>并不意味着什么。

Rust提供了一种创建包装器结构的简单方法:struct MyType(WrappedType);。那就是它。

一旦拥有自己的类型,添加索引很容易。有几种方法可以添加其他操作:

  • 如果只有少数操作有意义,那么明确添加是最好的。
  • 如果需要进行许多操作,并且您不介意暴露下面是Vec<X>的事实,那么您可以公开它:
    • 将其公开:struct MyType(pub WrappedType);,然后用户可以致电.0进行访问。
    • 通过实施AsRefAsMut,或创建一个getter。
    • 通过实施DerefDerefMut(这是隐含的,请确保您真的想要)。

当然,打破封装后来会很烦人,因为它也会阻止不变量的维护,所以我认为这是最后的解决方案。

答案 1 :(得分:4)

  

我更喜欢存储&#34;参考&#34;节点作为u32而不是usize。因此,当遍历图形时,我继续检索相邻的顶点&#34;引用&#34;,然后我用它来查找Vec对象中的实际顶点对象

所以实际上你并不想要u32,因为你永远不会对它进行计算,u32很容易让你做数学。你想要一个索引类型,它只能做索引,但其值是不可变的。

我建议你按照rustc_data_structures::indexed_vec::IndexVec的方式实施一些内容。

此自定义IndexVec类型不仅在元素类型上是通用的,而且在索引类型上也是通用的,因此允许您在NodeId周围使用u32 newtype包装器。您永远不会意外地使用非身份u32进行索引,并且您可以像使用u32一样轻松地使用它们。您甚至不必通过从向量长度计算它们来创建任何这些索引,而是push方法返回刚刚插入元素的位置的索引。