Using Trait Object for Struct - ERROR: wrong number of type arguments

Using Trait Object for Struct - ERROR: wrong number of type arguments

我是 Rust 的新手,我在使用“Trait Object”时遇到问题...

目前,我有 App 结构和 panels 字段,它是 WavePanel 结构的 Vec,实现了 Panel 特征。
因为我有更多的实现 Panel,我希望 panels 变得更通用。
因此,我尝试将 Panel 指定为该字段的特征对象,但它不起作用....

这是目前的样子(更改前):

https://github.com/minagawah/perlin-experiment/blob/6e8064140daedc0767733898621c951619ff4467/src_for_wasm/perlin-wave/src/app.rs#L14

use crate::panels::wave::WavePanel;
use crate::panels::Panel;

#[derive(Clone, Debug)]
pub struct App {
    points: Vec<Point>,
    points_prev: Vec<Point>,
    panels: Vec<WavePanel>, // <-- `WavePanel` struct works just fine.
}

impl App {
    pub fn new(config: &Config) -> Result<Self, String> {
        let color: String = config.color.clone();
        let color2: String = config.color2.clone();

        let mut panels = vec![];
        for panel in &config.panels {
            let id = panel.id.clone();
            match id.as_str() {
                "wave" => {
                    panels.push(WavePanel::new(
                        id.as_str(),
                        color.as_str(),
                        color2.as_str(),
                    )?);
                }
                _ => {}
            }
        }

        Ok(App {
            points: vec![],
            points_prev: vec![],
            panels: panels,
        })
    }
}

这是 Panel 特征:

pub trait Panel<G: Graphics> {
    fn g(&self) -> Rc<RefCell<G>>;

    fn reset(&mut self) {
        if let Ok(mut g) = self.g().try_borrow_mut() {
            let (width, height) = g.size();
            g.reset(width, height);
        };
    }
}

这就是 WavePanel 实现 Panel 特征的方式:

#[derive(Clone, Debug)]
pub struct WavePanel {
    id: String,
    g: Rc<RefCell<WaveGraphics>>,
    graph_type: Rc<Cell<GraphType>>,
}

impl Panel<WaveGraphics> for WavePanel {
    fn g(&self) -> Rc<RefCell<WaveGraphics>> {
        self.g.clone()
    }
}

而且,这是我尝试过的(之后):

use crate::panels::wave::WavePanel;
use crate::panels::Panel;

#[derive(Clone, Debug)]
pub struct App {
    points: Vec<Point>,
    points_prev: Vec<Point>,
    panels: Vec<Box<dyn Panel>>, // <-- This does not work...
}

impl App {
    pub fn new(config: &Config) -> Result<Self, String> {
        let color: String = config.color.clone();
        let color2: String = config.color2.clone();

        let mut panels = vec![];
        for panel in &config.panels {
            let id = panel.id.clone();
            match id.as_str() {
                "wave" => {
                    // Pushing it into Box this time.
                    panels.push(Box::new(
                        WavePanel::new(
                            id.as_str(),
                            color.as_str(),
                            color2.as_str(),
                        )?
                    ));
                }
                _ => {}
            }
        }

        Ok(App {
            points: vec![],
            points_prev: vec![],
            panels: panels,
        })
    }
}

这是错误:

error[E0107]: wrong number of type arguments: expected 1, found 0
  --> src/app.rs:15:25
   |
15 |     panels: Vec<Box<dyn Panel>>,
   |                         ^^^^^ expected 1 type argument

error: aborting due to previous error

For more information about this error, try `rustc --explain E0107`.
error: could not compile `perlin-wave`

Box<dyn Panel> 不够明确吗?
试了很多东西,还是不行...
拜托,我非常需要你的帮助....

编辑:已解决 (2021.3.4)

对于特征对象的错误使用,kmdreko 是正确的。我所拥有的特质不是Panel而是Panel<G: Graphics>,它们完全不同。
正如 kmdreko 提到的,我停止将 G 喂给 Panel 特征,并将 G 替换为 dyn Graphics(对于字段 g),这就成功了!
它解决了最初的错误。

然而,又出现了一个问题...
当我实际将派生 Panel 特征的结构 WavePanel 推送到 panels: Vec<Box<dyn Panel>> 时,我收到错误消息:expected trait object "dyn Panel", found struct "WavePanel"。这是关于实现异构 vec 的问题,不是 kmdreko 的错。就原问题而言,kmdreko的回答应该是正确答案。
为此,我在.
中找到了解释 所以,这是关于 Rust 在本地推断 WavePanel 结构而不是 dyn Panel trailt 对象。就在我创建 Box::new(WavePanel::new(..)) 时,现在我明确地告诉我想要特征对象 Vec<Box<dyn Panel>>,它修复了它。

还有一个问题....
既然涉及到主题,我觉得也值得留个脚注...
因此,我在 Panel 中的字段 g 现在在 Panel 中具有 dyn Graphics 而不是 GGraphics 特征现在也发生了类似的情况。就像我有 WavePanel 结构用于 Panel 特征一样,我有 WaveGraphics 结构用于 Graphics 特征。在某种程度上,Rust 现在与 Panel 中定义的 g 字段的类型混淆了......对于这个问题,我决定为 Graphics 特征派生 Any 特征。只要我将 as_any_mut() 定义为总是 return Any struct in Graphics trait,当我真正想要使用它时,例如 g.draw(),我可以始终将特征对象转换为 Any,并执行此操作:g.as_any_mut().downcast_mut::<WaveGraphics>() .

找到最终差异(针对所有修复)here

Shouldn't Box<dyn Panel> be explicit enough?

不,您已将 Panel 定义为通用; Panel<A>Panel<B> 是不同的特征。如果你想Panel不管图形类型都使用,就不能通用。

如果 g() 只是为了支持 reset(),您可以删除它:

pub trait Panel {
    fn reset(&mut self);
}

impl Panel for WavePanel {
    fn reset(&mut self) {
        if let Ok(mut g) = self.g.try_borrow_mut() {
            let (width, height) = g.size();
            g.reset(width, height);
        };
    }
}

或者如果 g() 仍然需要一般地获取图形对象,也将其设为动态:

pub trait Panel {
    fn g(&self) -> Rc<RefCell<dyn Graphics>>;
                           // ^^^^^^^^^^^^

    fn reset(&mut self) {
        if let Ok(mut g) = self.g().try_borrow_mut() {
            let (width, height) = g.size();
            g.reset(width, height);
        };
    }
}

impl Panel for WavePanel {
    fn g(&self) -> Rc<RefCell<dyn Graphics>> {
        self.g.clone()
    }
}