Rust编译器无法推断有关泛型类型的足够信息

lsu*_*und 0 generics rust

我正在学习Rust,并遇到类似的事情

struct A<T> {
    some_vec: Vec<T>,
    pub secret: &'static str
}

struct B{}

struct C{}

impl B {
    fn foo<T>(&self) {

        let bar: A<T> = A { 
            some_vec: Vec::new(), 
            secret: "123" 
        };

        println!("The secret is {}", bar.secret);
    }
}

impl C {
    fn foo<T>(&self) {
        let b = B{};
        b.foo();
    }
}

fn main() {
    let c = C{};
    c.foo();
}
Run Code Online (Sandbox Code Playgroud)

这会产生编译器错误

error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [--explain E0282]
  --> src/main.rs:26:11
   |>
26 |>         b.foo();
   |>           ^^^
Run Code Online (Sandbox Code Playgroud)

我看过有关同一错误消息的帖子,但在这种情况下我无法找出解决方案.b.foo()我缺少哪些信息(相关)?

Mat*_* M. 8

由于类型推断对于许多来到Rust的人来说是一个新奇事物,让我们更深入地解释一下.

从本质上讲,类型推断有点像你可能在杂志上玩过的那些"迷宫"游戏:

在此输入图像描述

你有一堆左边未知类型的地方,右边是少数已知类型.如何?那么,通过检查类型之间的关系!

最简单的关系(无需猜测)是一个1度的关系:

let x: String = "Hello, World".into();
Run Code Online (Sandbox Code Playgroud)

在Rust中,我们知道它into()来自Into<T>实现的特性&str,但是哪个T?好吧,into()返回a T并且表达式的类型应该是a String,因此它必须Into<String>.

因此,为了解决类型推断,编译器将在需要推断类型的位置和已知类型之间构建某种关系图(在Rust中,函数签名必须是显式的,因此它不应该也需要搜索远),然后将尝试一点一点地推断出类型.


我们来看看当前的用例:

fn main() {
    let c = C{};
    c.foo();
}
Run Code Online (Sandbox Code Playgroud)

在这里,c.foo();电话C::foo<T>():我们需要推断T.我们有什么信息?没有.小人物.纳达.

在这种情况下,无法解决问题,编译器挽救并询问您(开发人员)您想要T的是什么.您可以通过多种方式指定它:

  • 的一般方法是利用所谓的"turbofish"操作符::<>,如c.foo::<i32>()
  • 在无法推导出结果的特定情况下,您可以简单地将类型归类为左侧变量,如 let x: i32 = ...;
  • 应该注意的是,通常你不需要提供一个完整的类型,并且可以利用该_字符来消除它的一部分,let x: Vec<_> = ...;或者c.foo::<Vec<_>>()如果编译器有足够的信息来自行推断_.