何时应该使用直接访问 Rust Vec 而不是 get 方法?

7
Rust支持两种访问向量元素的方法:
let mut v = vec![1, 2, 3];

let first_element = &v[0];

let second_element = v.get(1);
get()方法返回一个Option类型,这似乎是一个有用的安全特性。C语言风格的语法&v[0]打字更短,但放弃了安全保障,因为无效读取会导致运行时错误,而不是产生指示读取超出界限的结果。
我不清楚何时需要使用直接访问方法,因为它似乎唯一的优点就是打字更快(我可以节省3个字符)。我是否看漏了其他优点(例如加速)?我想我会节省匹配表达式的条件,但与成本相比,这似乎并没有提供多少好处。

2
据我所知,它们中没有一个更快:括号语法也执行边界检查(这就是为什么如果您越界,它会出现恐慌而不是段错误)。 - Boiethios
@Boiethios 难道我不是仍然可以节省解包 Option 的成本吗(即匹配)?我认为这并不是很大的节省,但它并不完全相同。 - John Doucette
2
作为经验法则,我会说,如果您不希望出现越界访问(即它表示编程错误或代码中的其他严重问题),那么在索引运算符中使用 panic 停止执行是可以接受的。如果您在正常执行期间预计会出现越界访问(例如,它取决于外部输入),则需要捕获此情况并改用 .get - MB-F
@Boiethios 这只有在你在 C 中也使用对象指针时才会发生,因为在 C 中你可以直接访问对象,是的,Option 会增加开销。 - Stargateur
@Stargateur 不,阅读我链接的答案。 - Boiethios
显示剩余3条评论
1个回答

14

由于它们都执行边界检查,因此它们两个都不会更快。事实上,你的问题相当通用,因为还有其他一对方法,其中一个会 panic,而另一个返回选项,比如 String::reserveString::try_reserve

  • 如果你确定你的下标在范围内,请使用方括号版本。这只是一个语法上的捷径,等价于 get().unwrap()
  • 如果你不确定,请使用 get() 方法并进行检查。
  • 如果你确实需要最大速度不能使用迭代器已经通过基准测试确定索引是瓶颈你确定下标在范围内,那么可以使用 get_unchecked() 方法。但要小心,因为它是unsafe的;最好尽量避免在代码中使用任何unsafe块。

一个小建议:如果你关心程序性能,尽量避免使用这些方法,尽可能使用迭代器。例如,在第一个案例中有一百万个边界检查,第二个案例比第一个案例更快:

let v: Vec<_> = (0..1000_000).collect();

for idx in 0..1000_000 {
    // do something with v[idx]
}

for num in &v {
    // do something with num
}

我认为 get 操作有点慢。我进行了几次基准测试,显示了性能差异。虽然不是很明显。 - Quoc-Hao Tran
@Quoc-HaoTran 在发布版中有什么不同(使用--release标志)? - Boiethios
不,我不这么认为。 - Quoc-Hao Tran
@Quoc-HaoTran 好的,每个与性能相关的测试都必须在发布版本进行。开发版本不保证有任何优化,并且它不是用于部署到生产环境的。 - Boiethios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接