【问题标题】:How do I make a Collection of Generically Typed Structs in Rust?如何在 Rust 中创建泛型结构的集合?
【发布时间】:2018-09-02 03:34:11
【问题描述】:

我正在使用 Rust 创建一个基于文本的垄断游戏作为个人项目。我目前的设置是将各种空间作为自己的结构(例如,Property

use space::Event;

pub struct Property {
    message: String,
}

impl Property {
    pub fn new() -> Property {
        let message = String::from("Hello World!");
        Property { message: message }
    }
}

impl Event for Property {
    fn event(&self) {
        print!("{}", &self.message);
    }
}

还有一个通用的 Space 结构,它包含其中一种空格类型的实例(例如Space<Property>Space<Chance>)。

pub trait Event {
    fn event(&self);
}

pub struct Space<T> {
    item: T,
}

impl<T: Event> Space<T> {
    pub fn new(item: T) -> Space<T> {
        Space { item: item }
    }

    pub fn event(&self) {
        &self.item.event();
    }
}

每种类型的空间都实现了一个特征,要求它有一个“事件”方法,通用空间结构可以调用该方法。然后我有一个 Game 结构,它将包含某种空间集合(除其他外)。

pub struct Game {
    spaces: Vec<Space>, // Does not work
}

很遗憾,我在创建此集合时遇到了问题。无论我尝试哪一个,它都告诉我必须为 Space 指定一个类型参数。如何制作通用类型的结构集合?如果我可以通过索引拉出特定空间会更好,因为当我开始实现某些Chance 卡时,这将更容易将您移动到稍后的特定空间。抱歉,如果我遗漏了一些明显的东西,我是 Rust 的新手,所以我不一定知道要寻找什么。

【问题讨论】:

    标签: list generics collections rust


    【解决方案1】:

    Rust 编译器需要知道 Vec 中的每个元素有多大才能决定如何布局内存(每个元素必须占用相同的空间)。你的 Space 结构有一个类型参数 T 所以不清楚 Space 将占用多少空间,除非你也提供类型参数。例如。 Vec&lt;Space&lt;i32&gt;&gt; 会起作用。

    如果您想要不同大小的对象的Vec,一种常见的方法是使用trait objects 的向量。在您的示例中,您可以有一个 Vec&lt;Box&lt;Event&gt;&gt;,一个实现 Event 特征的对象向量,这里 vec 的每个元素都是一个 Box(智能指针),指向实现 Event 的堆分配类型。

    pub trait Event {
        fn event(&self);
    }
    
    pub struct Property {
        message: String,
    }
    
    impl Property {
        pub fn new(message: String) -> Property {
            Property { message }
        }
    }
    
    impl Event for Property {
        fn event(&self) {
            println!("{}", &self.message);
        }
    }
    
    pub struct Utility {
        message: String,
    }
    
    impl Utility {
        pub fn new(message: String) -> Utility {
            Utility { message }
        }
    }
    
    impl Event for Utility {
        fn event(&self) {
            println!("{}", &self.message);
        }
    }
    
    pub struct Game {
        pub spaces: Vec<Box<Event>>,
    }
    
    fn main () {
        let game = Game{ 
            spaces: vec![
                Box::new(Utility::new(String::from("Water works"))),
                Box::new(Property::new(String::from("Fleet Street"))),
                Box::new(Utility::new(String::from("Electric company"))),
                Box::new(Property::new(String::from("Bond Street"))),
            ] 
        };
    
        for space in game.spaces {
            space.event();
        }
    }
    
    // Water works
    // Fleet Street
    // Electric company
    // Bond Street
    

    【讨论】:

    • 注意:在 Rust 2018 中,我们更喜欢使用 dyn 关键字为用作特征对象的特征添加前缀。所以Vec&lt;Box&lt;dyn Event&gt;&gt; 会更惯用:)
    • 谢谢!我还不知道智能指针,但你的解释很有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 2022-11-23
    相关资源
    最近更新 更多