首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >锈病的泛型/性状:“预期'Foo<B>',发现‘Foo<Foo2>’‘”

锈病的泛型/性状:“预期'Foo<B>',发现‘Foo<Foo2>’‘”
EN

Stack Overflow用户
提问于 2014-09-26 15:56:40
回答 1查看 473关注 0票数 4

我问了一个类似的question earlier,它帮助我理解了引擎盖下面发生了什么,但当涉及到通用编程时,我仍然不能让Rust做我希望它做的事情。下面是一些代码:

代码语言:javascript
复制
struct Foo<B: Bar> { bars: Vec<Box<B>> }

struct Foo2;

trait Bar {}

impl Bar for Foo2 {}

impl<B: Bar> Foo<B> {
  fn do_something() -> Foo<B> {
    let foo2:Box<Bar> = box Foo2;
    let mut foo = Foo { bars: vec!(box Foo2) };
    foo.bars.push(box Foo2);
    foo // compiler: *ERROR*
  }
}

错误:expected 'Foo<B>', found 'Foo<Foo2>'

  1. 我如何给编译器一个提示或显式地告诉编译器foo (Foo)实现了Bar (B: Bar)?
  2. 这是个虫子吗?我是否应该推迟使用锈菌,直到它达到1.0?

版本:0.12.0-nightly (4d69696ff 2014-09-24 20:35:52 +0000)

我发现了@Levans解决方案的问题:

代码语言:javascript
复制
struct Foo2;

struct Foo3 {
  a: int
}

trait Bar {
    fn create_bar() -> Self;
}

impl Bar for Foo2 {
    fn create_bar() -> Foo2 { Foo2 } // will work
}

impl Bar for Foo3 {
    fn create_bar(a: int) -> Foo3 { Foo3 {a: a} } // will not work
}

错误:method 'create_bar' has 1 parameter but the declaration in trait 'Bar::create_bar' has 0

另外,我注意到了这一点:Bar::create_bar()。Rust如何知道如何使用Foo2的实现?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-26 17:03:53

当您使用<B: Bar>定义函数时,您告诉编译器“您可以在此函数B中使用实现特征Bar的任何类型替换”。

例如,如果您还创建了一个struct Foo3实现特性Bar,那么编译器就可以使用BFoo3调用do_something,这在当前实现中是不可能的。

在您的情况下,您的do_something函数尝试创建一个B对象,因此需要一种通用的方法来实现,这是由Bar特性给出的,例如,作为一个create_bar()方法,如下所示:

代码语言:javascript
复制
struct Foo<B: Bar> { bars: Vec<Box<B>> }

struct Foo2;

trait Bar {
    fn create_bar() -> Self;
}

impl Bar for Foo2 {
    fn create_bar() -> Foo2 { Foo2 }
}

impl<B: Bar> Foo<B> {
  fn do_something() -> Foo<B> {
    let mut foo = Foo { bars: vec!(box Bar::create_bar()) }; 
    foo.bars.push(box Bar::create_bar());
    foo 
  }
}

编辑答案:

在您的代码中,它确实无法工作,因为您希望向create_bar传递更多的参数,这是不可能的,因为它不尊重create_bar不带任何参数的特性定义。

但是像这样的事情不会有任何问题:

代码语言:javascript
复制
struct Foo2;

struct Foo3 {
  a: int
}

trait Bar {
    fn create_bar() -> Self;
}

impl Bar for Foo2 {
    fn create_bar() -> Foo2 { Foo2 }
}

impl Bar for Foo3 {
    fn create_bar() -> Foo3 { Foo3 {a: Ou} }
}

要点是:如果没有通用的方法,do_something函数就不能创建Bar对象,这种方法不依赖于<B>中的哪种类型,只要它实现了Bar。这就是泛型的工作原理:如果调用do_something::<Foo2>(),就好像在函数的整个定义中用Foo2代替了B

然而,我怀疑您真正想要做的是存储不同的类型,在同一个Vec中实现所有的Bar (否则将一个Box封装在里面将是非常无用的),您可以通过特性对象来实现这一点,并且它不需要泛型:

代码语言:javascript
复制
struct Foo<'a> { bars: Vec<Box<Bar + 'a>> }

struct Foo2;

trait Bar {}

impl Bar for Foo2 {}

impl<'a> Foo<'a> {
  fn do_something() -> Foo<'a> {
    let mut foo = Foo { bars: vec!(box Foo2 as Box<Bar>) };
    foo.bars.push(box Foo2 as Box<Bar>);
    foo
  }
}

基本上,属性对象是对对象的引用或指针,作为属性进行转换:

代码语言:javascript
复制
let foo2 = Foo2;
let bar = &foo2 as &Bar; // bar is a reference to a Trait object Bar

正如我的例子中所提供的,它也适用于盒子。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26063593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档