在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
创建一个包装类,但这也意味着必须编写许多函数包装器。有没有更优雅的方法来解决这个问题?
答案 0 :(得分:6)
如果没有明确的用例,很难推荐最佳方法。
这里基本上有两个问题:
u32
作为索引吗?使用函数式编程样式时,通常不需要索引,因为您操作迭代器。在这种情况下,Vec
仅为Index
实现usize
这一事实并不重要。
如果您的算法确实需要建立索引,那么为什么不使用usize
?有很多方法可以从u32
转换为usize
,在最后一刻转换可能是一种可能性,但是还有其他网站可以进行转换,如果找到阻塞点(或创建)只有少数几次转换,你才能逃脱。
至少,这是YAGNI的观点。
个人而言,作为一个类型怪物,我倾向于包装很多东西。我只是想添加语义信息,因为让我们面对它Vec<i32>
并不意味着什么。
Rust提供了一种创建包装器结构的简单方法:struct MyType(WrappedType);
。那就是它。
一旦拥有自己的类型,添加索引很容易。有几种方法可以添加其他操作:
Vec<X>
的事实,那么您可以公开它:
struct MyType(pub WrappedType);
,然后用户可以致电.0
进行访问。AsRef
和AsMut
,或创建一个getter。Deref
和DerefMut
(这是隐含的,请确保您真的想要)。当然,打破封装后来会很烦人,因为它也会阻止不变量的维护,所以我认为这是最后的解决方案。
答案 1 :(得分:4)
我更喜欢存储&#34;参考&#34;节点作为u32而不是usize。因此,当遍历图形时,我继续检索相邻的顶点&#34;引用&#34;,然后我用它来查找Vec对象中的实际顶点对象
所以实际上你并不想要u32
,因为你永远不会对它进行计算,u32
很容易让你做数学。你想要一个索引类型,它只能做索引,但其值是不可变的。
我建议你按照rustc_data_structures::indexed_vec::IndexVec
的方式实施一些内容。
此自定义IndexVec
类型不仅在元素类型上是通用的,而且在索引类型上也是通用的,因此允许您在NodeId
周围使用u32
newtype包装器。您永远不会意外地使用非身份u32
进行索引,并且您可以像使用u32
一样轻松地使用它们。您甚至不必通过从向量长度计算它们来创建任何这些索引,而是push
方法返回刚刚插入元素的位置的索引。