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

时间:2016-08-28 20:46:28

标签: 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();
}

这会产生编译器错误

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();
   |>           ^^^

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

2 个答案:

答案 0 :(得分:8)

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

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

enter image description here

左手边有一堆未知类型的地方,右手连接少数已知类型。如何?好吧,通过检查类型之间的关系!

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

let x: String = "Hello, World".into();

在Rust中,我们知道into()来自Into<T>实施的&str特征,但是T?好吧,into()返回T,表达式的类型应为String,因此必须Into<String>

为了解决类型推断,编译器因此会在需要推断类型的位置和已知类型之间构建某种关系图(在Rust中,函数签名必须是显式的,所以它不应该有搜索得太远了,然后会尝试逐渐推断出类型。

让我们检查当前的用例:

fn main() {
    let c = C{};
    c.foo();
}

此处,c.foo();调用C::foo<T>():我们需要推断T。我们有什么信息?没有。小人物。纳达。

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

  • 一般方法是利用所谓的&#34; turbofish&#34; ::<>
  • 中的运算符c.foo::<i32>()
  • 在无法推断出结果的特定情况下,您可以简单地将类型归类为左侧变量,如let x: i32 = ...;
  • 应该注意的是,您经常需要提供完整的类型,并且可以使用_字符来忽略部分内容,如let x: Vec<_> = ...;c.foo::<Vec<_>>()如果编译器有足够的信息来自行推断_

答案 1 :(得分:3)

通常,泛型函数将在其参数类型中使用其类型参数。在这种情况下,编译器可以根据调用中的参数类型推断类型参数。

但是,在您的情况下,B::fooC::foo没有使用T的任何参数。因此,每次调用都需要明确指定T的具体类型。这是通过在括号之前的函数名称之后添加::<X>(其中X是一个类型)来完成的。

C::foo中,您可能希望将C::foo的{​​{1}}转发给T,所以您要写:

B::foo

然后在impl C { fn foo<T>(&self) { let b = B {}; b.foo::<T>(); } } 中,您可以使用您想要的任何类型:

main