Generics 错误:无法推断有关``的足够类型信息;需要类型批注或泛型参数绑定

Generics 错误:无法推断有关``的足够类型信息;需要类型批注或泛型参数绑定,generics,rust,Generics,Rust,为通用标题道歉 下面是一些示例代码: use std::marker::PhantomData; pub trait Foo { fn foo(&self); } pub trait Bar<A: Foo> { fn bar(&self, a: A); } pub struct Test<A, B> where A: Foo, B: Bar<A> { _phantom_r: Phanto

为通用标题道歉

下面是一些示例代码:

use std::marker::PhantomData;

pub trait Foo {
    fn foo(&self);
}

pub trait Bar<A: Foo> {
    fn bar(&self, a: A);
}

pub struct Test<A, B>
    where A: Foo,
          B: Bar<A>
{
    _phantom_r: PhantomData<A>,
    bars: Vec<B>,
}

impl<A, B> Test<A, B>
    where A: Foo,
          B: Bar<A>
{
    pub fn new() -> Test<A, B> {
        Test {
            _phantom_r: PhantomData,
            bars: Vec::new(),
        }
    }

    pub fn add_bar(&mut self, b: B) {
        self.bars.push(b);
    }
}

fn main() {
    let t = Test::new();
}
错误:

<anon>:36:28: 36:46 error: the trait `core::marker::Sized` is not implemented for the type `Foo` [E0277]
<anon>:36     let t = Test::new() as Test<Foo,Bar<Foo>>;
:36:28:36:46错误:没有为类型'Foo`[E0277]实现trait'core::marker::Sized'
:36让t=Test::new()作为测试;
我有两个主要问题:

  • 为什么Rust无法推断
    测试的特征类型
  • 使此代码工作的解决方案是什么

  • 简单的回答是,您没有告诉它使用哪种类型

    解释你的声明:

    pub trait Foo {}
    
    “有一个特征
    Foo


    “如果你给我类型
    A
    ,它实现
    Foo
    ,和
    B
    ,它实现
    Bar)

    ,简单的回答是你没有告诉它使用什么类型

    解释你的声明:

    pub trait Foo {}
    
    “有一个特征
    Foo


    “如果您给我类型
    A
    ,它实现
    Foo
    ,和
    B
    ,它实现
    Bar)

    ,您可以将第一个错误归结为:

    fn main() {
        let v = Vec::new();
    }
    
    这里的问题是编译器无法确定向量将包含哪些具体类型。在本例中,您创建了一个结构(
    Test
    ),该结构可以在不传递
    a
    B
    的具体类型的情况下创建,但基本推理是相同的

    第二个问题是相关的。
    Foo
    Bar
    都不是编译时已知大小的具体类型。尝试在需要固定大小(由
    size
    trait表示)的位置使用它们将失败


    实例化类型时,必须知道类型的大小,这是通过提供具体类型来代替泛型类型参数来实现的

    您可以将第一个错误归结为:

    fn main() {
        let v = Vec::new();
    }
    
    这里的问题是编译器无法确定向量将包含哪些具体类型。在本例中,您创建了一个结构(
    Test
    ),该结构可以在不传递
    a
    B
    的具体类型的情况下创建,但基本推理是相同的

    第二个问题是相关的。
    Foo
    Bar
    都不是编译时已知大小的具体类型。尝试在需要固定大小(由
    size
    trait表示)的位置使用它们将失败


    实例化类型时,必须知道类型的大小,这是通过提供具体类型来代替泛型类型参数来实现的

    关于已接受答案的说明-已接受答案涵盖了识别特征的问题,但该线索中有一些注释解释了该问题的其他细节。为了便于阅读,我在这里总结了其中一个(因为评论有点难读)

    (当您使用上面代码中的特征时使用)将无法处理向量上的多个具体类型

    例如,以这个例子:

    trait Foo {
        fn method(&self) -> String;
    }
    impl Foo for u8 {
        fn method(&self) -> String {
            format!("u8: {}", *self)
        }
    }
    
    impl Foo for String {
        fn method(&self) -> String {
            format!("string: {}", *self)
        }
    }
    
    struct Test<T: Foo> {
        foos: Vec<T>,
    }
    impl<T:Foo> Test<T> {
        pub fn do_something(&self, x: T) {
            self.foos.push(x);
        }
    }
    
    fn main() {
        let x = 5u8;
        let y = "Hello".to_string();
    
        let t = Test {foos:Vec::new()};
        t.do_something(x);
        t.do_something(y);
    }
    
    它会起作用的。
    main()
    函数根本不需要更改(除了删除向量之外),它完全与导致静态调度(显然)不起作用的向量有关


    在这种情况下,我相信它会起作用——但我对它还不够熟悉,还没有给出任何深入的答案/示例。希望这对未来的读者有所帮助。

    关于已接受答案的说明-已接受答案涵盖了识别特征的问题,但该线索中有一些注释解释了该问题的其他细节。为了便于阅读,我在这里总结了其中一个(因为评论有点难读)

    (当您使用上面代码中的特征时使用)将无法处理向量上的多个具体类型

    例如,以这个例子:

    trait Foo {
        fn method(&self) -> String;
    }
    impl Foo for u8 {
        fn method(&self) -> String {
            format!("u8: {}", *self)
        }
    }
    
    impl Foo for String {
        fn method(&self) -> String {
            format!("string: {}", *self)
        }
    }
    
    struct Test<T: Foo> {
        foos: Vec<T>,
    }
    impl<T:Foo> Test<T> {
        pub fn do_something(&self, x: T) {
            self.foos.push(x);
        }
    }
    
    fn main() {
        let x = 5u8;
        let y = "Hello".to_string();
    
        let t = Test {foos:Vec::new()};
        t.do_something(x);
        t.do_something(y);
    }
    
    它会起作用的。
    main()
    函数根本不需要更改(除了删除向量之外),它完全与导致静态调度(显然)不起作用的向量有关


    在这种情况下,我相信它会起作用——但我对它还不够熟悉,还没有给出任何深入的答案/示例。希望这对未来的读者有所帮助。

    回答得不错。另一件事是编译器的推理范围相当高,因此如果代码满足推理机制,则可能会忽略类型参数。。通过使用
    add_foo
    add_bar
    方法,如下所示:谢谢你们的评论!在回答克里斯时,我最大的问题就是你把西蒙带大了!我的问题是,我无法提供像Chris示例中那样的具体类型,即:
    MyA
    MyB
    结构。我之所以使用traits,是因为我没有一个具体的类型——我添加了多种类型,就像Simon的例子一样。尽管如此,也许我的设计是错误的。不可能接受在单个函数中实现同一接口的多个具体类型吗?也就是说,
    MyB
    MyC
    implement
    Foo
    ,以及
    Test::add_bar()
    implements都接受a
    B
    ,但似乎
    add_bar()
    只接受一个具体类型,而不是类型上的特征。思想?也许我从根本上误解了Rust对Traits的实现(我认为它们更像是Go接口)@FizzBazer也许你想要一个?@Shepmaster似乎是这样,谢谢!对于其他人来说,我想我发现了设计上的一个问题。静态分派通过创建备用的、特定于类型的方法来工作——但这与向量不兼容。如果要将它们存储在数据结构中(我想象vector、hashmap等),则不能在编译时通过静态分派进行复制。因此,如果使用向量,显然需要动态调度。我还没有使用动态调度,所以
    struct MyA {}
    impl Foo for MyA {
        fn foo(&self) { println!("MyA::foo"); }
    }
    
    struct MyB {}
    impl Bar<MyA> for MyB {
        fn bar(&self, a: MyA) { println!("MyB::bar"); }
    
    }
    
    fn main() {
        let test = Test::<MyA, MyB>::new();
    }
    
    fn main() {
        let v = Vec::new();
    }
    
    trait Foo {
        fn method(&self) -> String;
    }
    impl Foo for u8 {
        fn method(&self) -> String {
            format!("u8: {}", *self)
        }
    }
    
    impl Foo for String {
        fn method(&self) -> String {
            format!("string: {}", *self)
        }
    }
    
    struct Test<T: Foo> {
        foos: Vec<T>,
    }
    impl<T:Foo> Test<T> {
        pub fn do_something(&self, x: T) {
            self.foos.push(x);
        }
    }
    
    fn main() {
        let x = 5u8;
        let y = "Hello".to_string();
    
        let t = Test {foos:Vec::new()};
        t.do_something(x);
        t.do_something(y);
    }
    
    struct Test {
    }
    impl Test {
        pub fn do_something<T: Foo>(&self, x: T) {
            x.method();
        }
    }