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
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.
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..10
1..
..10
..
1..=10
..=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
.