【问题标题】:Using Trait Object for Struct - ERROR: wrong number of type arguments使用 Struct 的特征对象 - 错误:类型参数的数量错误
【发布时间】:2021-02-28 02:49:23
【问题描述】:

我是 Rust 的新手,我在使用“特征对象”时遇到了问题...

现在,我有 App 结构和 panels 字段,它是实现 Panel 特征的 WavePanel 结构的 Vec。
因为我有更多的实现 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 trait 的方式:

#[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&lt;dyn Panel&gt; 不应该足够明确吗?
尝试了很多东西,但仍然没有运气...
拜托,我非常需要你的帮助......

编辑:已解决 (2021.3.4)

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

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

还有一个问题....
由于它与主题有关,我认为也值得留个便条...
所以,我在Panel 中有字段g 现在在Panel 中有dyn Graphics 而不是GGraphics trait 现在也发生了类似的情况。就像我对 Panel 特征有 WavePanel 结构一样,我对 Graphics 特征有 WaveGraphics 结构。在某种程度上,Rust 现在与在Panel 中定义的g 字段的类型混淆了...对于这个问题,我决定为Graphics 特征派生Any 特征。只要我在Graphics trait 中定义as_any_mut() 总是返回Any struct,当我真正想使用它时,例如g.draw(),我总是可以将trait 对象转换为Any,然后做这个:g.as_any_mut().downcast_mut::&lt;WaveGraphics&gt;()

对于最终差异(对于所有修复),请找到 here

【问题讨论】:

    标签: rust traits


    【解决方案1】:

    Box&lt;dyn Panel&gt; 不应该足够明确吗?

    不,您已将 Panel 定义为泛型; Panel&lt;A&gt;Panel&lt;B&gt; 是不同的特征。如果你希望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()
        }
    }
    

    【讨论】:

    • 我将保留g(),因为Panel trait 不知道属于WavePanel 结构的g 字段。但是,对于dyn Graphics,耶!这是一个重大突破!谢谢!不过,现在我得到:expected trait object "dyn Panel", found struct "WavePanel" for my vec panels... 这是我应用的修复程序的diff
    • 这是关于将不同类型推送到异构 vec panels,这是一个完全不同的问题。所以,我想说,对于最初的问题,你是对的!谢谢,kmdoreko!仅供参考,对于我申请新问题的解决方案,我在上面留下了编辑说明。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多