在方括号内的下标中,“两个点”运算符是什么意思?

27

我正在浏览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>>

这正是我预期的,但我仍然不理解[..]在这个上下文中的含义。它在这里的意思不仅仅是将cmd中的第一个String作为&str传递吗?如果是这样,那写cmd[1]是否等效?为什么他们要这样做?

2个回答

27

..是范围运算符,可在Rust书的操作符和符号附录中找到六种不同的形式:

  1. Range1..10
  2. RangeFrom1..
  3. RangeTo..10
  4. RangeFull..
  5. RangeInclusive1..=10
  6. RangeToInclusive..=10

如果没有任何元素占据端点位置,则该范围沿着该方向“无限延伸”。

这与Index特质(或IndexMut,如果需要执行修改)相结合。在您的示例中,您有一个字符串切片(类似,见下一点),您正在对其进行索引操作:"foo"[2..]

具体来说,&str实现了Index,如下所示:

返回给定字符串从字节范围内的切片

然后还有第三个人性化的功能:通过Deref(或类似情况下的DerefMut)进行操作。 String通过返回&str来实现Deref,因此可以在String上使用任何可用于&str的方法。


12
这只是一种从String&str的显式强制转换方式。 在这种情况下,[..]实际上是不必要的,因为Deref强制转换意味着parse_name(&args[1])也是有效的:&String将隐式借用为&str[ ]索引运算符调用std::ops::Index特质,并且..语法会创建一个 std::ops::RangeFull。由于std::env::args()返回一个String的迭代器,cmd 是一个Vec<String>
因此,foo[..] 语法调用了 StringIndex<RangeFull> 实现(您可以在 Index 页面的实现者列表中看到)。实现 如下所示:
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所需的。


4
所以总的来说,&cmd[1][..] 的意思是“将 cmd 中索引为 1 的字符串的每个字符作为一个字符串切片”? - Jared
4
没错 - 这是准确的!“从cmd[1]的开头取一个片段,到cmd[1]的结尾,包括结尾在内”。 - daboross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接