Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does the "two periods" operator mean in the context of a subscript inside of square brackets?

Tags:

syntax

rust

I was looking through Rust's source code to better acquaint myself with the language. I came across this snippet.

// Collect program arguments as a Vec<String>.
let cmd: Vec<_> = env::args().collect();

// Some unrelated code omitted here.

match subcommand::parse_name(&cmd[1][..]) {
    // It did some stuff here.
}

I didn't understand the [..]. So, I went and checked out the declaration of parse_name:

pub fn parse_name(name: &str) -> Option<Box<Subcommand>>

It's what I expected, but I still don't get the [..]. What does it mean in this context? Isn't it just passing the first String in cmd as a &str? If so, is this equivalent to just writing cmd[1]? Why did they do it this way?

like image 916
Jared Avatar asked Aug 03 '15 22:08

Jared


2 Answers

Two periods (..) is the range operator. You can find this in the Operators and Symbols Appendix of the Rust book. There are six flavors:

  1. Range: 1..10
  2. RangeFrom: 1..
  3. RangeTo: ..10
  4. RangeFull: ..
  5. RangeInclusive: 1..=10
  6. RangeToInclusive: ..=10

When no item occupies an end position, the range goes on "forever" in that direction.

This combines with the Index trait (or IndexMut, if mutation is required). In your example, you have a string slice (kind of, see next point) that you are applying indexing to: "foo"[2..].

Specifically, &str implements Index as

Returns a slice of the given string from the byte range

Then there's a third bit of ergonomics happening: Deref (or DerefMut in similar cases). String implements Deref by returning a &str, so any method available to a &str is available to a String.

like image 72
Shepmaster Avatar answered Nov 01 '22 08:11

Shepmaster


This is just a way to explicitly coerce from String to &str. In this case, the [..] is actually unnecessary as Deref coercions means that parse_name(&args[1]) is valid too: &String will borrow to &str implicitly.

The [ ] indexing operator is calling the std::ops::Index trait, and the .. syntax is creating a std::ops::RangeFull value. cmd is a Vec<String>, since std::env::args() returns an Iterator over Strings.

Hence, the foo[..] syntax is calling the implementation of Index<RangeFull> for String (which you can see in the list of Implementors on the Index page). The implementation looks like:

impl ops::Index<ops::RangeFull> for String {
    type Output = str;

    #[inline]
    fn index(&self, _index: ops::RangeFull) -> &str {
        unsafe { mem::transmute(&*self.vec) }
    }
}

The &*self.vec is borrowing the String's internal Vec<u8> to &[u8], and then the transmute is explicitly casting that to a &str, which is safe because String's API ensures that the internal Vec<u8> is valid UTF-8, which is what str requires.

like image 10
huon Avatar answered Nov 01 '22 08:11

huon