我可以创建任何类型的向量:
let mut vec: Vec<u32> = Vec::new();
new()
如何知道什么是请求的矢量元素类型时(不像c++),它不是参数化与类型名称?
另一方面:我可以显式指定类型吗?这似乎不能编译:
let mut vec = Vec<u32>::new();
Rust编译器使用(稍作修改的)Hindley-Milner类型推断算法。基本上,您在源代码中提供的所有类型信息都用作未绑定泛型类型参数的约束,然后约束求解器尝试找出所有未知数。对于赋值
let vec: Vec<u32> = Vec::new();
右边有一个未绑定的泛型参数——Vec<T>
的T
参数。编译器会记住尚未确定的未绑定类型参数。通过查看Vec::new()
的原型,编译器可以看到它返回Vec<T>
,因此右边的表达式类型为Vec<T>
,而T
仍然未绑定。根据左边的类型注释,编译器知道该类型应该是Vec<u32>
,因此它可以推断T
必须是u32
。
这是一个相对简单的例子。约束求解器也能够处理更复杂的情况。
可以在右侧使用"turbofish"显式指定类型。操作符::<>
:
let vec = Vec::<u32>::new();
另一方面:我可以显式指定类型吗?这似乎不能编译:
let mut vec = Vec<u32>::new();
使用<>
来指定泛型参数在表达式上下文中是不明确的,因为<
可以是"小于"运营商。
因此,当你想在表达式上下文中显式指定泛型参数时,你需要使用所谓的"turbofish";消歧操作符:
let mut vec = Vec::<u32>::new();
这样的区别纯粹是语法上的。
new()
如何知道什么是请求的向量元素类型时(不像c++)它不是参数化与类型名称?
您要查找的术语是类型推断:编译器从上下文中推断类型的能力,而无需显式指定。
不同语言有不同的类型推断算法:
- c++有单向类型推断:表达式的类型可以在不指定的情况下推断,允许使用
auto
来声明变量。 - Java在泛型的另一个方向上有单向类型推断:
HashMap<String, String> map = new HashMap<>();
. Rust有双向类型推断,因为它使用了Hindley-Milner的一个变体,所以你很少需要在函数体中指定类型。
为了便于说明,想象如下(Playground链接):
fn display(i: u64) {
println!("{}", i);
}
fn main() {
let mut vec = Vec::new();
vec.push(1);
display(vec[0]);
}
编译器将按照以下方式进行推理:
vec
的类型为Vec<?0>
。Vec<?0>::push
接受{integer}
作为参数,因此?0
是{integer}
。<Vec<?0> as Index>::Output
是?0
.display
接受u64
作为参数,因此?0
就是u64
。
这个链接的组合(通过线程?0
)允许它收集两个约束:
?0
是{integer}
.?0
是u64
.
由于?0
是u64
,这两个约束都被满足,那么它被推断为u64
。
然而,如果您将display
更改为&str
,那么您将得到一个错误消息,因为推理将失败:
error[E0308]: mismatched types --> src/main.rs:10:17 | 10 | display(vec[0]); | ^^^^^^ expected `&str`, found integer
因为同时满足?0 = &str
和?0 is {integer}
是不可能的。
当为泛型类型实现某些东西时,编译器足够聪明地省略该类型。如果在变量中直接指定类型,则更多。
省略类型到Vec<u32>
let mut vec = Vec::new();
vec.push(0u32);
变量声明:
let mut vec: Vec<u32> = Vec::new();
类型especification:
let mut vec = Vec::<u32>::new();
游乐场