为什么 Rust 有时在泛型参数前加 ::?

9
在 Rust 中声明类型为 vector 或 hash map 的变量时,我们需要这样做:
let v: Vec<int>
let m: HashMap<int, int>

为了实例化,我们需要调用new()。然而,我们这样做:

Vec::<int>::new()
   ^^
HashMap::<int, int>::new()
       ^^

请注意::的突然出现。对于来自C++的人来说,这些都很奇怪。为什么会出现这种情况?在IDENTIFIER :: < IDENTFIER …中有一个前导的::是否使得解析更容易,而IDENTIFIER < IDENTIFIER则可能被解释为小于操作?(因此,这只是为了使语言更易于解析?但如果是这样,为什么不在类型规范中也这样做,以便两者相互呼应?)
(正如Shepmaster所指出的,通常Vec::new()已经足够了;类型通常可以推断出来。)

2
在Rust中它们不被称为“模板”;我认为你的C++正在表现出来。:-) 出于个人经验,我从未见过特定用法的类型参数指定。使用类型推断,您只需说Vec::new()即可。我只看到过像parsecollect这样返回trait并且必须选择具体类型的函数才需要指定类型。 - Shepmaster
@Shepmaster: 啊,它们是泛型类型吧?是的,一定程度的类型推断可以避免您需要指定实际类型;我认为作为 Rust 的新手,我大多数时间都是偶然发现这一点,还在想为什么。 - Thanatos
我认为这是一个好问题;我甚至没有意识到您可以在那个位置指定类型参数!我期待着答案,但我的猜测是它会归结于解析的简单性,正如你所建议的那样。我只是想评论一下,表明您的示例代码并不常见,希望能帮助其他阅读此问题的新手。干杯! - Shepmaster
在大多数情况下,类型推断确实可以解决问题,但有些函数具有类型参数,这些参数既不出现在参数中,也不出现在返回值中,在这种情况下,您必须使用该语法。这样一个函数的例子是 std::mem::size_of() - Vaelden
2个回答

12

解析表达式时,一个<究竟是类型参数列表的开始还是小于号操作符很模糊不清。Rust总是假设它是后者,并要求使用::<表示类型参数列表。

解析类型时,它总是明确为类型参数列表,因此不需要使用::<

在C++中,这种歧义保留在解析器中,这使得解析C++比解析Rust更加困难。有关为什么这很重要的解释,请参见此处

无论如何,在Rust中,大多数情况下都可以推断出类型,您只需编写Vec::new()即可。由于::<通常不需要并且相当丑陋,因此将类型中的两个语法匹配起来没有意义,而应该只保留<


你知道在变量声明时不也复制语法的原因吗?比如 let v: Vec::<int> - Thanatos
我在最后进行了编辑,解决了这个问题。我认为,基本上,::< 很丑陋,我们尽量要避免使用它。在类型中使用 < 并且利用类型推断大多数情况下可以帮助我们避免使用它。 - Scott Olson
这是否被词法分析/语法分析为单个符号 ::< - Thanatos
不,如果你愿意的话,可以写成 :: < - Scott Olson
我感叹,如果 Rust 能够像 Scala 一样将 [ ] 保留给泛型,而不是浪费在数组索引上,那就好了。毕竟,( )apply 运算符同样适用于数组索引。 - mako

3
两种不同的语法甚至不一定指定相同的类型参数。
例如:
let mut map: HashMap<K, V>;
KV填充了struct HashMap声明中的类型参数,即类型本身。
在这个表达式中:
HashMap::<K, V>::new()
KV填充了impl块中定义new方法的类型参数!impl块不需要与类型本身具有相同、相同数量或相同默认类型参数。
在这种情况下,结构体具有参数HashMap<K, V, S = RandomState>(3个参数,1个默认)。包含::new()的impl块具有参数impl<K, V>(2个参数,未实现对任意状态的支持)。

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