我正在查看Rust的源代码,以便更好地熟悉该语言。我遇到了这个片段。
// 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.
}
我不明白[..]
。所以,我去检查了parse_name
的声明:
pub fn parse_name(name: &str) -> Option<Box<Subcommand>>
这是我的预期,但我仍然没有得到[..]
。在这种情况下它意味着什么?是不是只是将String
中的第一个cmd
作为&str
传递?如果是这样,这相当于只写cmd[1]
?他们为什么这样做?
这只是明确强制从String
到&str
的一种方式。在这种情况下,[..]
实际上是不必要的,因为Deref
强制意味着parse_name(&args[1])
也是有效的:&String
将隐含地借用&str
。
[ ]
索引运算符调用std::ops::Index
特征,而..
语法正在创建a std::ops::RangeFull
value。 cmd
是一个Vec<String>
,因为std::env::args()
返回an Iterator
over String
s。
因此,foo[..]
语法为Index<RangeFull>
调用String
的实现(您可以在Index
页面上的实现者列表中看到)。 implementation看起来像:
impl ops::Index<ops::RangeFull> for String {
type Output = str;
#[inline]
fn index(&self, _index: ops::RangeFull) -> &str {
unsafe { mem::transmute(&*self.vec) }
}
}
&*self.vec
借用String
的内部Vec<u8>
到&[u8]
,然后transmute
明确地将其投射到&str
,这是安全的,因为String
的API确保内部Vec<u8>
是有效的UTF-8,这是str
所需要的。
两个周期(..
)是范围运算符。你可以在Rust书的Operators and Symbols Appendix找到这个。有六种口味:
Range
:1..10
RangeFrom
:1..
RangeTo
:..10
RangeFull
:..
RangeInclusive
:1..=10
RangeToInclusive
:..=10
当没有项目占据结束位置时,该范围在该方向上“永远”。
这与Index
特征(或IndexMut
,如果需要突变)相结合。在您的示例中,您有一个字符串切片(有点,见下一点),您正在应用索引:"foo"[2..]
。
具体来说,&str
实施Index
从字节范围返回给定字符串的切片
然后有第三点人体工程学发生:Deref
(或类似情况下的DerefMut
)。 String
通过返回Deref
来实现&str
,因此任何&str
可用的方法都可用于String
。