7

Rust supports two methods for accessing the elements of a vector:

let mut v = vec![1, 2, 3];

let first_element = &v[0];

let second_element = v.get(1);

The get() method returns an Option type, which seems like a useful safety feature. The C-like syntax &v[0] seems shorter to type, but gives up the safety benefits, since invalid reads cause a run-time error rather than producing an indication that the read was out of bounds.

It's not clear to me when I would want to use the direct access approach, because it seems like the only advantage is that it's quicker to type (I save 3 characters). Is there some other advantage (perhaps a speedup?) that I'm not seeing? I guess I would save the conditional of a match expression, but that doesn't seem like it offers much benefit compared to the costs.

Boiethios
  • 38,438
  • 19
  • 134
  • 183
John Doucette
  • 4,370
  • 5
  • 37
  • 61
  • 2
    AFAIK, none of them is quicker: the bracket syntax performs also bound-checks (that's why it panics and does not segfault if you are out of bounds). – Boiethios Aug 17 '18 at 16:32
  • @Boiethios Don't I still save on the cost of unpacking the Option though (i.e. a match)? I don't think that's a big savings, but it's not _quite_ identical. – John Doucette Aug 17 '18 at 16:35
  • Not sure if I'm right, but there is no overhead with `Option`: you can see it as a C raw pointer: `None` is `NULL` and `Some` is the ok pointer value. – Boiethios Aug 17 '18 at 16:43
  • Related: https://stackoverflow.com/questions/16504643/what-is-the-overhead-of-rusts-option-type – Boiethios Aug 17 '18 at 17:23
  • 2
    As a rule of thumb I'd say if you don't expect out of bounds access (i.e. it indicates a programming error or another serious problem with your code) it's fine to stop execution by panic in the index operator. If you expect out of bounds access during normal execution (e.g. it depends on external input) you will want to catch this situation and use `.get` instead. – MB-F Aug 17 '18 at 18:51
  • @Boiethios That is only if you also use a pointer to the object in C, as you directly get to the object in C, yes Option add an overhead. – Stargateur Aug 17 '18 at 19:45
  • @Stargateur Nope, read the answer I linked. – Boiethios Aug 17 '18 at 19:54
  • @Boiethios I know option don't add size for pointer but that wasn't my point, I'm talking about runtime overhead. – Stargateur Aug 17 '18 at 19:58

1 Answers1

14

Neither of them is quicker because they both do bounds checks. In fact, your question is quite generic because there are other pairs of methods where one of them panics while the other returns an option, such as String::reserve vs String::try_reserve.

  • If you are sure that you are in bounds, use the brackets version. This is only a syntactic shortcut for get().unwrap().
  • If you are unsure of this, use the get() method and do your check.
  • If you critically need maximum speed and you cannot use an iterator and you have determined through benchmarks that the indexing is the bottleneck and you are sure to be in bounds, you can use the get_unchecked() method. Be careful about this because it is unsafe: it is always better to not have any unsafe block in your code.

Just a little bit of advice: if you are concerned by your program performance, avoid using those methods and prefer to use iterators as much as you can. For example, the second example is faster than the first one because in the first case there are one million bounds checks:

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
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Boiethios
  • 38,438
  • 19
  • 134
  • 183