5

I am working through the Rust book, namely the minigrep project. There I came across the following snippet:

fn main() {
    let args: Vec<String> = env::args().collect();

    let (query, filename) = parse_config(&args);

    // --snip--
}

fn parse_config(args: &[String]) -> (&str, &str) {
    let query = &args[1];
    let filename = &args[2];

    (query, filename)
}

The confusing piece for me is args: &[String]. If I replace it with args: &Vec<String>, it also works. My guess is that &[String] is a more general type annotation that matches not only &Vec<String>, but also some other types. Is that correct? If so, what other types are matched by [T]?

ljedrz
  • 20,316
  • 4
  • 69
  • 97
kreo
  • 2,613
  • 2
  • 19
  • 31

1 Answers1

7

Generally speaking, [T] is a contiguous sequence and &[T] is a slice.

The reason why the compiler allows &[String] instead of &Vec<String> is that Vec<T> dereferences to [T]. This is called Deref coercion. It can be said that the former notation (in function parameters) is more general; it is also the preferred one. Further details about automatic dereferencing rules can be found in this question.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • 1
    `[T]` is not an array, because arrays are `[T; N]` with a statically known size. The [slice documentation](https://doc.rust-lang.org/std/slice/) names `[T]` a *contiguous sequence*.. I'm not sure if this is the official term. – MB-F May 08 '18 at 07:54
  • In contrast, the [Reference](https://doc.rust-lang.org/reference/types.html#array-and-slice-types) says `[T]` is a *slice* and `&[T]` is a *shared slice* often just called *slice*. This gets confusing :) – MB-F May 08 '18 at 08:00
  • Yeah, it can be confusing; I guess `[T]`, `&[T]` and `&mut [T]` can all be referred to as slices, but the reference variants are most useful and thus that name stuck to them most. – ljedrz May 08 '18 at 09:31
  • NIT: [method call resolution](https://doc.rust-lang.org/reference/expressions/method-call-expr.html) (referenced in the last link) works slightly differently than type coercion when passing a parameter since `self` can implicitly introduce an indirection `T -> &T`, something that isn't done for normal parameters. – kmdreko Nov 16 '21 at 21:13