实现复制项目集合的最佳方法是什么?

时间:2015-05-27 22:39:05

标签: rust

我正在写第一个Rust的程序,它拿了一张卡片列表,并尝试从这些卡片中找到最好的套牌。 我想要一张可以复制到套牌的卡片目录。我试图找到这样做的惯用方法。我的第一个想法是包含每张卡片之一的矢量或数组,以及将该卡片的副本返回到卡片组的功能。

这是我的代码:

pub trait Card {
    fn get_name(&self) -> &String;
    fn get_card_type(&self) -> &CardType;
    fn get_cost(&self) -> Option<&i32>;

    fn play(&self){
        println!("Played {} for {} mana.", self.get_name(), self.get_cost().unwrap());
    }
}

pub enum CardType {
    Creature,
    Spell,
    Land,
}

pub struct Creature {
    pub name: String,
    pub card_type: CardType,
    pub cost: i32,
    pub attack: i32,
    pub defense: i32,
    pub tapped: bool,
}

impl Card for Creature{
    fn get_name(&self) -> &String {
        &self.name
    }

    fn get_card_type(&self) -> &CardType {
        &self.card_type
    }

    fn get_cost(&self) -> Option<&i32> {
        Some(&self.cost)
    }
}

pub struct Spell {
    pub name: String,
    pub card_type: CardType,
    pub cost: i32,
    pub damage: i32,
}

impl Card for Spell{
    fn get_name(&self) -> &String {
        &self.name
    }

    fn get_card_type(&self) -> &CardType {
        &self.card_type
    }

    fn get_cost(&self) -> Option<&i32> {
        Some(&self.cost)
    }
}

pub struct Land {
    pub name: String,
    pub card_type: CardType,
    pub tapped: bool,
}

impl Card for Land{
    fn play(&self) {
        println!("Played {}.", self.get_name());
    }

    fn get_name(&self) -> &String {
        &self.name
    }

    fn get_card_type(&self) -> &CardType {
        &self.card_type
    }

    fn get_cost(&self) -> Option<&i32> {
        None
    }
}

pub fn get_random_card() -> Box<Card> {
    Box::new( Creature{
        name: "My Card".to_string(), 
        card_type: CardType::Creature, 
        cost: 1, 
        attack: 2, 
        defense: 2,
        tapped: false,
    })
}

get_random_card()函数包含一个示例卡。所以基本上我只需要一个静态数组或卡片向量和一个函数将它们复制到一个套牌中,但我无法实现它。 有什么建议?随意指出我做错的其他事情。

编辑:一些澄清 -

此处的代码可以使用,但我想要一个包含可用卡列表的变量。例如

// some pseudocode, in file cards.rs
let cards = [
    Creature {
        name = "Creature 1"
        //...
    },
    Land {
        name = "Land 1"
        //...
    },
    Spell {
        name = "Spell 1"
        //...
    },
];

fn get_card(name) -> mut Card {
    // return a mutable copy/clone of a card, not a reference
}

我希望在一个单独的文件中将它声明在main函数之外。我试过几个不同的东西试图让编译器开心,但我很确定我错过了一些明显的东西。记忆目前不是一个大问题,“卡”var中不会有那么多卡。但甲板将动态生成,所以我需要在某处从卡片中取出卡片。

感谢。

1 个答案:

答案 0 :(得分:4)

如果您不担心分配太多内存,那么您现在就拥有了所需的一切:

fn main() {
    let hand: Vec<_> = (0..5).map(|_| get_random_card()).collect();
    for card in &hand {
        println!("{}", card.get_name());
    }
}

我们只需抓住5张卡并将其存储在Vec中。然后我们可以遍历矢量并打印出卡片名称。

如果你担心记忆而你想要“重复使用”一堆牌,你可以按照上面那样做,然后引用它们:

fn main() {
    let deck: Vec<_> = (0..52).map(|_| get_random_card()).collect();

    let hand1 = &deck[0..5];
    let hand2 = &deck[5..10];
    let hand3 = &deck[10..15];
    let hand4 = &deck[15..20];

    for card in hand1 {
        println!("{}", card.get_name());
    }
}

此处,编译器将阻止您在卡座超出范围后尝试使用卡。如果您需要更多灵活性,除了Rc之外,您还可以使用Box

use std::rc::Rc;

pub fn get_random_card() -> Rc<Box<Card>> {
    Rc::new(Box::new(Creature {
        name: "My Card".to_string(), 
        card_type: CardType::Creature, 
        cost: 1, 
        attack: 2, 
        defense: 2,
        tapped: false,
    }))
}

fn main() {
    let deck: Vec<_> = (0..52).map(|_| get_random_card()).collect();

    let hand1 = deck[0..5].to_owned();
    let hand2 = deck[5..10].to_owned();
    let hand3 = deck[10..15].to_owned();
    let hand4 = deck[15..20].to_owned();

    for card in &hand1 {
        println!("{}", card.get_name());
    }
}

这使每张卡可以管理活动参考的引用计数。当引用转到0时,卡被释放。

注意在Rust nightlies中,您只能使用Rc<T>代替Rc<Box<T>>

  

随意指出我做错的其他事情。

对我来说有三件事:

  1. 您应该在每个结构上使用#[derive(Debug)]。可能派生的其他内容包括Copy和/或ClonePartialEqHash。当然,您可以在添加之前等到其中一个,但Debug非常有用。
  2. 返回&str而不是&String。 99.9%的情况下,您希望使用&str代替&String - 它更灵活。
  3. 没有理由返回对CardTypei32等小类型的引用 - 只需直接返回它们。