7

What does &variable mean when it is used in patterns or closure arguments?

for &code in self.exit_code.iter() { ... }

let mut new_seps = do seps.iter().fold(~[]) |result, &next| { ... }

Here we have &code and &next in for loop and closure definition. What do & sign in these mean? Why cannot we simply use code and next, without the ampersand? Is it related to ref qualifier in pattern matching? Is it related to & in self argument in trait implementations?

I couldn't find anything on this syntax neither in current Rust reference manual nor in tutorial. Currently I think this is some kind of implicit dereferencing (this follows from error message which appears if I omit & in the pattern), but I'm not sure.

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • I'd say it means "capture by borrowing pointer" rather than "by value". – Kerrek SB Sep 28 '13 at 11:33
  • @KerrekSB, so does that mean that if in `|result, next|` `next` has type `T`, then in `|result, &next|` `next` has `&T` type? – Vladimir Matveev Sep 28 '13 at 11:58
  • I would have thought so, but I'm not sure, either. As you say, the manual is a bit lacking in that regard... this should be easy enough to try, though! – Kerrek SB Sep 28 '13 at 11:59
  • Well, removing or adding `&` in my code leads to rather cryptic message. My example may be a bit complex though... – Vladimir Matveev Sep 28 '13 at 12:02
  • If you have a pointer type, I think you must dereference with `*` (though there are cases of auto-dereferencing, like array subscripts); so if you try to omit the `*` and it really is passed by borrowing pointer, you should see an error to that effect. (I can try it myself later when I'm at a machine with a rust compiler.) – Kerrek SB Sep 28 '13 at 12:08
  • @KerrekSB, I'm using `next` in a comparison: `if next == "\\s" { ... }`, and omitting `&` gives `error: mismatched types: expected `&&str` but found `&'static str` (expected &-ptr but found &'static str)`. If `&` is present then all is OK. It seems that there is a problem when using static lifetimes... I'll check it later. – Vladimir Matveev Sep 28 '13 at 12:32
  • What about `if *next == "\\s"`? – Kerrek SB Sep 28 '13 at 12:34
  • @KerrekSB, yes, explicit dereference works, exactly as follows from dbaupp's answer. Thank you. – Vladimir Matveev Sep 28 '13 at 16:54

1 Answers1

11

It's a pattern match, "destructuring" something of type &T. That is, in

let &x = &1i; 

x has type int, and value 1. So it's actually the opposite to ref (which does what @KerrekSB is saying, ref x captures by reference rather than by value).

One can regard it as similar to

match returns_an_option() {
    Some(a) => { ... }
    None => { ... }
}

except the constructor of &T is &, not Some or None.


In this specific instance, I guess seps is a vector (the error you state indicates it's probably a &[&str]), so the .iter() returns an object that implements Iterator<& &str>, that is, it is an iterator over references to the elements of the vector (&str), thus, you need to dereference next somehow to get to the original &str. This can be done by & in a pattern match (as the code demonstrates) or with *next when it is used.

(Note that the & patterns only work with implicitly copyable types, as one cannot move ownership out from a reference/borrowed pointer (i.e. &T).)

huon
  • 94,605
  • 21
  • 231
  • 225
  • Yeah, you're entirely correct. It is `&[&str]` vector. I didn't catch that `iter()` returns `Iterator<&T>` instead of `Iterator`, hence the confusion. So, it really is some kind of implicit dereference, and it also goes nicely with pattern match semantics, as I suspected. Thank you very much. – Vladimir Matveev Sep 28 '13 at 16:53