如何在Rust中创建一般类型的结构集合?

问题描述 投票:1回答:1

我正在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();
    }
}

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

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

不幸的是,我遇到了创建此集合的问题。无论我尝试哪一个,它都告诉我必须为Space指定一个类型参数。如何制作通常键入的结构集合?如果我可以通过其索引拉出一个特定的空间,那将是更好的选择,因为这将使我更容易实现某些Chance卡,这些卡将您带到特定的空间后面。抱歉,如果我遗漏了一些明显的东西,我是Rust的新手,所以我并不总是知道要找什么。

list generics collections rust
1个回答
2
投票

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

如果你想要一个不同大小的物体的Vec,一个常见的方法是使用trait objects的矢量。在你的例子中,你可以有一个Vec<Box<Event>>,一个实现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
© www.soinside.com 2019 - 2024. All rights reserved.