【问题标题】:How to make a Rust Generic Struct/Trait require a Box<other trait>?如何使 Rust Generic Struct/Trait 需要 Box<other trait>?
【发布时间】:2021-10-01 16:40:17
【问题描述】:

我有一个特征Agent 代表模拟中的代理,还有一个结构SimpleAgent 实现了这个特征。由于Agent 的大小在编译时是未知的,所以我的代码一般使用Vec&lt;Box&lt;dyn Agent&gt;&gt; 我想创建一个通用特征AgentCollection&lt;T&gt; 并使用AgentTree&lt;T&gt; 结构实现它。

到目前为止,我有以下内容:

pub trait AgentCollection<T> {
    fn new(agents: Vec<Box<T>>) -> Self;
    fn get_in_rectilinear_range(point: vec::Vec2, range: f64) -> Vec<Box<T>>;
    fn get_in_euclidean_range(point: vec::Vec2, range: f64) -> Vec<Box<T>>;
}

pub struct AgentTree<T: agent::Agent> {
    left: Option<Box<AgentTree<T>>>,
    right: Option<Box<AgentTree<T>>>,
    node: Box<T>,
}

#[allow(unused)]
impl<T: agent::Agent> AgentTree<T> {
    fn range_search(point: vec::Vec2, range: f64) -> std::vec::Vec<Box<T>> {
        todo!()
    }
}

impl<T: agent::Agent> AgentCollection<T> for AgentTree<T> {
    fn new(agents: std::vec::Vec<Box<T>>) -> Self {
        todo!()
    }

    fn get_in_rectilinear_range(point: vec::Vec2, range: f64) -> std::vec::Vec<Box<T>> {
        todo!()
    }

    fn get_in_euclidean_range(point: vec::Vec2, range: f64) -> std::vec::Vec<Box<T>> {
        todo!()
    }
}

这都是类型检查。但是,当我在我的主文件中使用它时,例如

let agent_tree = AgentTree::new(last_agents);

last_agents 的类型为 std::vec::Vec&lt;std::boxed::Box&lt;dyn agent::Agent&gt;&gt;,我收到错误 the size for values of type 'dyn agent::Agent' cannot be known at compilation time

我想我想以某种方式将AgentTree 类型参数限制为Box&lt;agent::Agent 而不仅仅是agent::Agent,以便调整大小,但我不知道该怎么做。例如,我尝试过:pub struct AgentTree&lt;T: Box&lt;agent::Agent&gt;&gt; { ... }

【问题讨论】:

    标签: generics rust traits box


    【解决方案1】:

    默认情况下,泛型类型参数将有一个Sized trait 绑定,它需要一个大小的类型。但是像dyn Agent 这样的特征对象没有大小,它们可以表示多种类型,因此在编译时无法知道它们的大小。

    要使您的代码与 dyn Agent 一起工作,您只需在 trait bound 中添加 ?Sized 以删除默认的 Sized trait bound:

    pub trait AgentCollection<T: ?Sized> {
    //                           ^^^^^^
        fn new(agents: Vec<Box<T>>) -> Self;
        fn get_in_rectilinear_range(point: vec::Vec2, range: f64) -> Vec<Box<T>>;
        fn get_in_euclidean_range(point: vec::Vec2, range: f64) -> Vec<Box<T>>;
    }
    
    pub struct AgentTree<T: ?Sized + agent::Agent> {
    //                      ^^^^^^
        left: Option<Box<AgentTree<T>>>,
        right: Option<Box<AgentTree<T>>>,
        node: Box<T>,
    }
    
    #[allow(unused)]
    impl<T: ?Sized + agent::Agent> AgentTree<T> {
    //      ^^^^^^
        fn range_search(point: vec::Vec2, range: f64) -> std::vec::Vec<Box<T>> {
            todo!()
        }
    }
    
    impl<T: ?Sized + agent::Agent> AgentCollection<T> for AgentTree<T> {
    //      ^^^^^^
        fn new(agents: std::vec::Vec<Box<T>>) -> Self {
            todo!()
        }
    
        fn get_in_rectilinear_range(point: vec::Vec2, range: f64) -> std::vec::Vec<Box<T>> {
            todo!()
        }
    
        fn get_in_euclidean_range(point: vec::Vec2, range: f64) -> std::vec::Vec<Box<T>> {
            todo!()
        }
    }
    

    【讨论】:

      【解决方案2】:

      想通了,我添加了以下内容:

      type BoxedAgent = Box<dyn agent::Agent>;
      

      然后用BoxedAgent 代替Box&lt;T: agent::Agent&gt;

      打算暂时搁置一下,以防有人有更好的建议。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多