Vec::new() 如何知道请求的元素类型是什么?

ard*_*bro 5 rust

我可以创建任何类型的向量,如下所示:

let mut vec: Vec<u32> = Vec::new();
Run Code Online (Sandbox Code Playgroud)

new()当(与 C++ 不同)未使用类型名称参数化时,如何知道所请求的向量元素类型是什么?

另一方面:我可以明确指定类型吗?这似乎无法编译:

let mut vec = Vec<u32>::new();
Run Code Online (Sandbox Code Playgroud)

Sve*_*ach 11

Rust 编译器使用(稍作修改的)Hindley-Milner 类型推断算法。基本上,您在源代码中提供的所有类型信息都用作未绑定泛型类型参数的约束,然后约束求解器尝试找出所有未知数。在分配的情况下

\n
let vec: Vec<u32> = Vec::new();\n
Run Code Online (Sandbox Code Playgroud)\n

右侧 \xe2\x80\x93 的参数有一个未绑定的泛型类型T参数Vec<T>。编译器会记住尚未确定的未绑定类型参数。通过查看 的原型Vec::new(),编译器可以看到它返回Vec<T>,因此右侧的表达式具有类型Vec<T>,但T仍处于未绑定状态。根据左侧的类型注释,编译器知道该类型应该是Vec<u32>,因此它可以推断出T必须是u32。

\n

这是一个比较简单的案例。约束求解器还能够处理更复杂的情况。

\n

您可以使用“turbofish”运算符在右侧显式指定类型::<>:

\n
let vec = Vec::<u32>::new();\n
Run Code Online (Sandbox Code Playgroud)\n


Mat*_* M. 7

另一方面:我可以明确指定类型吗?这似乎无法编译:

let mut vec = Vec<u32>::new();
Run Code Online (Sandbox Code Playgroud)

使用<>来指定通用参数在表达式上下文中是不明确的,其中<可能是“小于”运算符。

因此,每当您想在表达式上下文中显式指定通用参数时,您需要使用所谓的“turbofish”运算符来消除歧义:

let mut vec = Vec::<u32>::new();
Run Code Online (Sandbox Code Playgroud)

这样的区别纯粹是语法上的。


new()当(与 C++ 不同)未使用类型名称参数化时,如何知道所请求的向量元素类型是什么?

您正在寻找的术语是类型推断:编译器从上下文推断类型的能力,而无需显式指定。

不同的语言有不同的类型推理算法:

  • C++ 具有单向类型推断:可以在不指定表达式的情况下推断表达式的类型,从而允许使用 来auto声明变量。
  • Java 在泛型的另一个方向上有单向类型推断:HashMap<String, String> map = new HashMap<>();。
  • Rust 具有双向类型推断,因为它使用 Hindley-Milner 的变体,因此您很少需要在函数体内指定类型。

出于说明目的,请想象以下内容(游乐场链接):

fn display(i: u64) {
    println!("{}", i);
}

fn main() {
    let mut vec = Vec::new();

    vec.push(1);
    
    display(vec[0]);
}
Run Code Online (Sandbox Code Playgroud)

编译器会按照以下方式进行推理:

  1. vec有类型Vec<?0>.
  2. Vec<?0>::push采用 an{integer}作为参数,因此?0是 an {integer}。
  3. <Vec<?0> as Index>::Output是?0。
  4. display采用 au64作为参数,因此?0是u64。

这种链接组合(线程?0通过)允许它收集 2 个约束:

  • ?0是一个{integer}。
  • ?0是u64。

?0由于a满足这两个约束u64,因此推断它是 a u64。

但是,如果您更改display为采用 a &str,那么您将收到一条错误消息,因为推理将失败:

error[E0308]: mismatched types
  --> src/main.rs:10:17
   |
10 |         display(vec[0]);
   |                 ^^^^^^ expected `&str`, found integer
Run Code Online (Sandbox Code Playgroud)

因为同时满足是不可能的?0 = &str。?0 is {integer}